Performance Difference Between save() and saveAll() in Spring Data – Spring Data中save()和saveAll()之间的性能差异

最后修改: 2020年 11月 19日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

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

在这个快速教程中,我们将了解Spring Data中save()saveAll()方法之间的性能差异。

2. Application

2.应用

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

为了测试性能,我们需要一个带有实体和存储库的Spring应用程序。

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

3.业绩

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

为了测试性能,我们将使用这两种方法保存10000本书。

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

首先,我们将使用 save()方法。

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:

然后,我们将创建一个图书列表,并使用saveAll()方法一次性保存所有的图书。

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.

在我们的测试中,我们注意到,第一种方法花了大约2秒,第二种方法花了大约0.3秒。

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.

此外,当我们启用JPA批量插入时,我们观察到save()方法的性能下降了10%,而saveAll()方法的性能则增加了60%。

4. Differences

4.差异

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.

查看这两个方法的实现,我们可以看到 saveAll()迭代了每个元素,并在每次迭代中使用save()方法。这意味着它不应该有如此大的性能差异。

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

更仔细地观察,我们发现这两个方法都有@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.

此外,默认的事务传播类型是REQUIRED,这意味着,如果不提供,每次调用这些方法时都会创建一个新的事务

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().

在我们的案例中,每次我们调用save()方法,都会创建一个新的事务,而当我们调用saveAll()时,只创建一个事务,并在之后被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

5.总结

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

在这篇文章中,我们已经了解了Spring Data中save()saveAll()方法之间的性能差异。

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.

像往常一样,这些例子的代码可以在GitHub上找到over