Spring JPA Hibernate - JpaRepository Insert (Batch)
14 Sep 2017How to use batch in spring data JpaRepository
Configuration for batch size
spring:
jpa:
properties:
hibernate.jdbc.batch_size: 4
Rewrite INSERT statements into multi-value inserts (only for MySQL)
- append
&rewriteBatchedStatements=true
tospring.datasource.url
Verification by db log (MySQL as example)
$ mysqld --verbose --help | grep -A 1 "Default options"
mysql> SET GLOBAL log_output = "FILE";
mysql> SET GLOBAL general_log_file = "/path/to/your/logfile.log";
mysql> SET GLOBAL general_log = 'ON';
$ tail -f /path/to/your/logfile.log
SQL will be like:
178931 16:16:16 66 Query SELECT 1 566 Query SET autocommit=0 566 Query select @@session.tx_read_only 566 Query insert into emp (id, name, dep) values ('1', 'clark', 'IT'),('2', 'robin', 'Market'),('3', 'jeff', 'IT'),('4', 'emily', 'HR') 566 Query insert into emp (id, name, dep) values ('5', 'john', 'Sales')
How does spring data internally work ?
Add Insert Action
- call
SimpleJpaRepository.save
(org.springframework.data.jpa.repository.support) AbstractEntityManagerImpl.persist
(org.hibernate.jpa.spi)SessionImpl.persist
(org.hibernate.internal)SessionImpl.firePersist
(org.hibernate.internal)DefaultPersistEventListener.onPersist
(org.hibernate.event.internal)DefaultPersistEventListener.entityIsTransient
(org.hibernate.event.internal)JpaPersistEventListener.saveWithGeneratedId
(org.hibernate.jpa.event.internal.core)AbstractSaveEventListener.performSave
(org.hibernate.event.internal)AbstractSaveEventListener.performSaveOrReplicate
(org.hibernate.event.internal)AbstractSaveEventListener.addInsertAction
(org.hibernate.event.internal)ActionQueue.addAction
(org.hibernate.engine.spi)ActionQueue.addInsertAction
(org.hibernate.engine.spi)ActionQueue.addResolvedEntityInsertAction
(org.hibernate.engine.spi)- add
EntityInsertAction
intoEXECUTABLE_LISTS_MAP.get(AbstractEntityInsertAction)
Real insert execution when session flush
TransactionInterceptor.invoke
(org.springframework.transaction.interceptor): it is called by proxy of business class whose method with@Transactional
TransactionAspectSupport.commitTransactionAfterReturning
(org.springframework.transaction.interceptor): it is called after real business methodSessionImpl.beforeTransactionCompletion
(org.hibernate.internal)SessionImpl.flush
(org.hibernate.internal): get all flush type listeners’ (JpaFlushEventListener
set fromJpaIntegrator
)onFlush
DefaultFlushEventListener.onFlush
(org.hibernate.event.internal): call super’sperformExecutions
ActionQueue.executeActions
(org.hibernate.engine.spi): loopEXECUTABLE_LISTS_MAP.get(AbstractEntityInsertAction
to execute every action.EntityInsertAction.execute
(org.hibernate.action.internal): callSingleTableEntityPersister.insert
AbstractEntityPersister.insert
(org.hibernate.persister.entity): if use batch, add insert action to BatchingBatchBatchingBatch.addToBatch
(org.hibernate.engine.jdbc.batch.internal): if reached the batch_size, then perform executionBatchingBatch.performExecution
(org.hibernate.engine.jdbc.batch.internal)PreparedStatement.executeBatchInternal
(com.mysql.jdbc): should set rewriteBatchedStatements if want to execute within batch sqlPreparedStatement.executeBatchedInserts
(com.mysql.jdbc): Rewrites the already prepared statement into a multi-value insert and executes enw statement