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 .