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=truetospring.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
EntityInsertActionintoEXECUTABLE_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@TransactionalTransactionAspectSupport.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’ (JpaFlushEventListenerset fromJpaIntegrator)onFlushDefaultFlushEventListener.onFlush(org.hibernate.event.internal): call super’sperformExecutionsActionQueue.executeActions(org.hibernate.engine.spi): loopEXECUTABLE_LISTS_MAP.get(AbstractEntityInsertActionto execute every action.EntityInsertAction.execute(org.hibernate.action.internal): callSingleTableEntityPersister.insertAbstractEntityPersister.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