Performance Difference Between save() and saveAll() in Spring Data

1. Overview

In this quick tutorial, we’ll learn about the performance difference between save() and saveAll() methods in Spring Data.

2. Application

In order to test the performance, we’ll need a Spring application with an entity and a repository.

Let’s create a book entity:

@Entity
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private String title;
    private String author;

    // constructors, standard getters and setters
}

In addition, let’s create a repository for it:

public interface BookRepository extends JpaRepository<Book, Long> {
}

3. Performance

To test the performance, we’ll save 10,000 books using both methods.

First, we’ll use the save() method:

for(int i = 0; i < bookCount; i++) {
    bookRepository.save(new Book("Book " + i, "Author " + i));
}

Then, we’ll create a list of books and use the saveAll() method to save all of them at once:

List<Book> bookList = new ArrayList<>();
for (int i = 0; i < bookCount; i++) {
    bookList.add(new Book("Book " + i, "Author " + i));
}

bookRepository.saveAll(bookList);

In our tests, we noticed that the first method took around 2 seconds, and the second one took approximately 0.3 seconds.

Furthermore, when we enabled JPA Batch Inserts, we observed a decrease of up to 10% in the performance of the save() method, and an increase of up to 60% on the saveAll() method.

4. Differences

Looking into the implementation of the two methods, we can see that saveAll() iterates over each element and uses the save() method in each iteration. This implies that it shouldn’t be such a big performance difference.

Looking more closely, we observe that both methods are annotated with @Transactional.

Furthermore, the default transaction propagation type is REQUIRED, which means that, if not provided, a new transaction is created each time the methods are called.

In our case, each time we call the save() method, a new transaction is created, whereas when we call saveAll(), only one transaction is created, and it’s reused later by save().

This overhead translates into the performance difference that we noticed earlier.

Finally, the overhead is bigger when batching is enabled due to the fact that it’s done at the transaction level.

5. Conclusion

In this article, we’ve learned about the performance difference between the save() and saveAll() methods in Spring Data.

Ultimately, choosing whether to use one method over another can have a big performance impact on the application.

As always, the code for these examples is available over on GitHub.

Related posts:

Reading an HTTP Response Body as a String in Java
A Guide to Spring Cloud Netflix – Hystrix
Converting between an Array and a List in Java
Phương thức forEach() trong java 8
Java Program to Represent Graph Using 2D Arrays
A Custom Media Type for a Spring REST API
How to Get the Last Element of a Stream in Java?
Java Program to Implement Pagoda
Java Program to Implement SimpeBindings API
Java Program to Implement Patricia Trie
Introduction to Spring Boot CLI
Bootstrap a Web Application with Spring 5
Java Program to Solve the 0-1 Knapsack Problem
Java Program to Test Using DFS Whether a Directed Graph is Weakly Connected or Not
Java Program to Implement Fisher-Yates Algorithm for Array Shuffling
Java Program to implement Bi Directional Map
Java Program to Implement Ternary Search Algorithm
Comparing getPath(), getAbsolutePath(), and getCanonicalPath() in Java
Java Program to Check if a Matrix is Invertible
Java Program to Perform Postorder Non-Recursive Traversal of a Given Binary Tree
Java Program to Implement ConcurrentHashMap API
Ways to Iterate Over a List in Java
Thao tác với tập tin và thư mục trong Java
How to Delay Code Execution in Java
Map to String Conversion in Java
Hướng dẫn Java Design Pattern – Interpreter
Exploring the Spring Boot TestRestTemplate
Java Program to Generate a Graph for a Given Fixed Degree Sequence
Java Program to Repeatedly Search the Same Text (such as Bible by building a Data Structure)
Spring @RequestParam Annotation
CharSequence vs. String in Java
Returning Custom Status Codes from Spring Controllers