1. Обзор
Выход в базу данных стоит дорого. Возможно, мы сможем повысить производительность и согласованность, объединив несколько вставок в одну.
В этом уроке мы рассмотрим, как это сделать с помощью Spring Data JPA .
2. Хранилище Spring 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{ }
Это обнажает Сохранить все метод для нас, который будет объединять несколько вставок в одну.
Итак, давайте воспользуемся этим в контроллере:
@RestController public class CustomerController { @Autowired CustomerRepository customerRepository; @PostMapping("/customers") public ResponseEntityinsertCustomers() { 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 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 .