33

Would it make any difference if I do:

@Transactional
public void processData() {
    List<MyEntity> entities = ....;
    MyEntityRepository.save(entities);
}

vs.

@Transactional
public void processData() {
    List<MyEntity> entities = ....;
    for (MyEntity entity : entities) {
        MyEntityRepository.save(entity);
    }
}

What is the difference in terms of the underlying queries and performance?

BPm
  • 2,924
  • 11
  • 33
  • 51

4 Answers4

34

From SimpleJpaRepository:

@Transactional
public <S extends T> List<S> More save(Iterable<S> entities) {

    List<S> result = new ArrayList<S>();

    if (entities == null) {
        return result;
    }

    for (S entity : entities) {
        result.add(save(entity));
    }

    return result;
}

So, your second business method only shadows save(Iterable<S> entities) Crud Repository method, in the sense that it iterates the list and calls save(S) on your behalf.

As long as transaction is demarcated from your processData business method, there is no really a difference in performance or queries executed.

Ori Dar
  • 18,687
  • 5
  • 58
  • 72
  • If my list contains multiple Entities with the same primary key and then I call `save(List entities)`, it gives constraint exception. However, if I iterate (i.e the second business method), it doesn't complain. Why is that? – BPm Sep 26 '15 at 12:56
  • Interesting. My guess is that somehow `@Transactional` does not apply for `processData()`, so in the second variant every iteration runs within it's own transactional context, thus succeeds. – Ori Dar Sep 26 '15 at 19:13
  • @AshishLohia save method can be use both with single object or list of objects as parameter. One can think it will be helpful because it is "bulk insert" but as you see above it is not the case. – Sahin Yanlık Nov 06 '18 at 11:38
25

As what has been mentioned by Ori Dar, there is no really a difference.

However, there is one thing you should notice:the method used to a save a list of elements has been renamed into <S extends T> List<S> saveAll(Iterable<S> entities) in 2.2.0.M1 according to the repo history, and the save method no longer takes as argument a list.

Since I don't have 50 reputation to comment the answer or question above, I have to write a new answer about this change.

kayochin
  • 431
  • 6
  • 11
6

For SpringData Jpa, a cleaner approach will be to use repository.saveAll instead of a forloop with repository.save. saveAll will automatically iterate through the list and save it.

saveAll is a part of JpaRepository, so no need to define any method.

Rishabh Agarwal
  • 2,374
  • 1
  • 21
  • 27
  • This article details a performance difference test : https://www.baeldung.com/spring-data-save-saveall – Jonath P Feb 25 '22 at 12:55
2

saveAll is probably 5-20 times faster because it goes with 1 transaction when .save() opens a new transaction every time it executes. Making it with one and only transaction makes it faster and not more use memory sparingly

Proof: Spring data save vs saveAll performance https://www.baeldung.com/spring-data-save-saveall

  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 05 '21 at 09:53