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

Пакетные вставки Spring Data JPA

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

1. Обзор

Выход в базу стоит дорого. Возможно, мы сможем улучшить производительность и согласованность, объединив несколько вставок в одну.

В этом уроке мы рассмотрим, как это сделать с помощью Spring Data JPA .

2. Весенний репозиторий JPA

Во-первых, нам понадобится простая сущность. Назовем его Клиент :

@Entity
public class Customer {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;

// constructor, getters, setters
}

И затем нам нужен наш репозиторий:

public interface CustomerRepository extends CrudRepository<Customer, Long> {
}

Это предоставляет нам метод saveAll , который объединяет несколько вставок в одну.

Итак, давайте воспользуемся этим в контроллере:

@RestController
public class CustomerController {
@Autowired
CustomerRepository customerRepository;

@PostMapping("/customers")
public ResponseEntity<String> insertCustomers() {
Customer c1 = new Customer("James", "Gosling");
Customer c2 = new Customer("Doug", "Lea");
Customer c3 = new Customer("Martin", "Fowler");
Customer c4 = new Customer("Brian", "Goetz");
List<Customer> customers = Arrays.asList(c1, c2, c3, c4);
customerRepository.saveAll(customers);
return ResponseEntity.created("/customers");
}

// ... @GetMapping to read customers
}

3. Тестирование нашей конечной точки

Тестировать наш код просто с помощью MockMvc :

@Autowired
private MockMvc mockMvc;

@Test
public void whenInsertingCustomers_thenCustomersAreCreated() throws Exception {
this.mockMvc.perform(post("/customers"))
.andExpect(status().isCreated()));
}

4. Уверены ли мы, что собираем партии?

Так что, на самом деле, нужно сделать еще немного настройки — давайте сделаем быструю демонстрацию, чтобы проиллюстрировать разницу.

Во-первых, давайте добавим следующее свойство в application.properties , чтобы увидеть некоторую статистику:

spring.jpa.properties.hibernate.generate_statistics=true

На этом этапе, если мы запустим тест, мы увидим статистику, подобную следующей:

11232586 nanoseconds spent preparing 4 JDBC statements;
4076610 nanoseconds spent executing 4 JDBC statements;
0 nanoseconds spent executing 0 JDBC batches;

Итак, мы создали четырех клиентов, и это здорово, но обратите внимание, что ни один из них не был внутри партии.

Причина в том, что пакетная обработка в некоторых случаях не включена по умолчанию.

В нашем случае это потому, что мы используем автоматическую генерацию идентификатора. Таким образом, по умолчанию saveAll выполняет каждую вставку отдельно.

Итак, включаем:

spring.jpa.properties.hibernate.jdbc.batch_size=4
spring.jpa.properties.hibernate.order_inserts=true

Первое свойство указывает Hibernate собирать вставки партиями по четыре. Свойство order_inserts сообщает Hibernate, что нужно потратить время на группировку вставок по объектам, создавая большие пакеты.

Итак, во второй раз, когда мы запустим наш тест, мы увидим, что вставки были упакованы:

16577314 nanoseconds spent preparing 4 JDBC statements;
2207548 nanoseconds spent executing 4 JDBC statements;
2003005 nanoseconds spent executing 1 JDBC batches;

Мы можем применить тот же подход к удалениям и обновлениям ( помня, что Hibernate также имеет свойство order_updates ).

5. Вывод

Благодаря возможности пакетной вставки мы можем увидеть некоторый прирост производительности.

Мы, конечно, должны знать, что в некоторых случаях пакетная обработка автоматически отключается, и мы должны проверить и спланировать это перед отправкой.

Обязательно ознакомьтесь со всеми этими фрагментами кода на GitHub .