How to implement batch update using Spring Data Jpa?

I think this is not possible with Spring Data JPA according to the docs. You have to look at plain JDBC, there are a few methods regarding batch insert/updates.

However, you can do it with Hibernate fairly easy.


Following this example: Spring Data JPA Batch Inserts, I have created my own way of updating it without having to deal with EntityManager.

The way I did it is first to retrieve all the data that I want to update, in your case, it will be WHERE goodsId=:goodsId AND level=:level. And then I use a for loop to loop through the whole list and setting the data I want

List<GoodsPrice> goodsPriceList = goodsRepository.findAllByGoodsIdAndLevel();
for(GoodsPrice goods : goodsPriceList) {
  goods.setPrice({{price}});
}
goodsRepository.saveAll(goodsPriceList);

Some of the followings are needed for inserts or updated. having generate_statistics on so that you can see if you are really batching it

// for logging purpose, to make sure it is working
spring.jpa.properties.hibernate.generate_statistics=true
// Essentially key to turn it on
spring.jpa.properties.hibernate.jdbc.batch_size=4
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true

and the log is here

27315 nanoseconds spent acquiring 1 JDBC connections;
    0 nanoseconds spent releasing 0 JDBC connections;
    603684 nanoseconds spent preparing 4 JDBC statements;
    3268688 nanoseconds spent executing 3 JDBC statements;
    4028317 nanoseconds spent executing 2 JDBC batches;
    0 nanoseconds spent performing 0 L2C puts;
    0 nanoseconds spent performing 0 L2C hits;
    0 nanoseconds spent performing 0 L2C misses;
    6392912 nanoseconds spent executing 1 flushes (flushing a total of 3 entities and 0 collections);
    0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)

One more link to be added to this conversation for more reference

Spring Data JPA batch insert/update

Few things to be considered while trying a Batch Insert/ Update using Spring Data JPA

  1. GenerationType used for @Id creation of Entity
  2. Setting up of Batch size attribute of Hibernate Property
  3. Setting order_inserts (for making Batch_size effective on Insert statements) or order_updates (for making Batch_size effective on Update statements) attribute of Hibernate properties
  4. Setting batch_versioned_data in order to make order_updates effective for Batch_size implementation

If you're using Hibernate, you do have an option if you're willing to manager the transactions yourself.

Here is the test example

int entityCount = 50;
int batchSize = 25;

EntityManager entityManager = null;
EntityTransaction transaction = null;

try {
    entityManager = entityManagerFactory().createEntityManager();

    transaction = entityManager.getTransaction();
    transaction.begin();

    for ( int i = 0; i < entityCount; ++i ) {
        if ( i > 0 && i % batchSize == 0 ) {
            entityManager.flush();
            entityManager.clear();

            transaction.commit();
            transaction.begin();
        }

        Post post = new Post(String.format( "Post %d", i + 1 ) );
        entityManager.persist( post );
    }

    transaction.commit();
} catch (RuntimeException e) {
    if ( transaction != null && transaction.isActive()) {
        transaction.rollback();
    }
    throw e;
} finally {
    if (entityManager != null) {
        entityManager.close();
    }
}

It would also be recommended to set the following properties to something that fits your needs.

<property
    name="hibernate.jdbc.batch_size"
    value="25"
/>

<property
    name="hibernate.order_inserts"  
    value="true"
/>

<property
    name="hibernate.order_updates"  
    value="true"
/>

All of this was taken from the following article. The best way to do batch processing with JPA and Hibernate