Перейти к основному содержимому

Разница в производительности между save() и saveAll() в Spring Data

· 2 мин. чтения

1. Обзор

В этом кратком руководстве мы узнаем о разнице в производительности между методами save() и saveAll() в Spring Data.

2. Приложение

Чтобы проверить производительность, нам понадобится приложение Spring с сущностью и репозиторием.

Давайте создадим объект книги:

@Entity
public class Book {

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

private String title;
private String author;

// constructors, standard getters and setters
}

Кроме того, давайте создадим для него репозиторий:

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

3. Производительность

Чтобы проверить производительность, мы сохраним 10 000 книг, используя оба метода.

Во-первых, мы будем использовать метод save() :

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

Затем мы создадим список книг и воспользуемся методом saveAll() , чтобы сохранить их все сразу:

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

bookRepository.saveAll(bookList);

В наших тестах мы заметили, что первый метод занял около 2 секунд, а второй — около 0,3 секунды.

Кроме того, когда мы включили пакетные вставки JPA, мы наблюдали снижение производительности метода save() на 10 % и повышение производительности метода saveAll() на 60 % .

4. Отличия

Глядя на реализацию двух методов, мы видим, что saveAll() перебирает каждый элемент и использует метод save() на каждой итерации. Это означает, что не должно быть такой большой разницы в производительности.

Присмотревшись повнимательнее, мы замечаем, что оба метода аннотированы @Transactional .

Кроме того, тип распространения транзакции по умолчанию — REQUIRED, что означает, что если он не указан, новая транзакция создается каждый раз при вызове методов .

В нашем случае каждый раз, когда мы вызываем метод save() , создается новая транзакция, а когда мы вызываем saveAll() , создается только одна транзакция, и она повторно используется позже с помощью save() .

Эти накладные расходы превращаются в разницу в производительности, которую мы заметили ранее.

Наконец, накладные расходы больше при включении пакетной обработки из-за того, что она выполняется на уровне транзакции.

5. Вывод

В этой статье мы узнали о разнице в производительности между методами save() и saveAll() в Spring Data.

В конечном счете выбор того или иного метода может сильно повлиять на производительность приложения.

Как всегда, код этих примеров доступен на GitHub .