Как избежать прямой вставки JPA в базу данных?

#jpa

Вопрос:

Это таблица mysql.

 create table Customer
(
    id          int auto_increment   primary key,
    birth       date        null,
    createdTime time        null,
    updateTime  datetime(6) null
);
 

Это мой java-код

 @Before
public void init() {
    this.entityManagerFactory=Persistence.createEntityManagerFactory("jpaLearn");
    this.entityManager=this.entityManagerFactory.createEntityManager();
    this.entityTransaction=this.entityManager.getTransaction();
    this.entityTransaction.begin();
}
@Test
public void persistentTest() {
    this.entityManager.setFlushMode(FlushModeType.COMMIT); //don't work.
    for (int i = 0; i < 1000; i  ) {
        Customer customer = new Customer();
        customer.setBirth(new Date());
        customer.setCreatedTime(new Date());
        customer.setUpdateTime(new Date());
        this.entityManager.persist(customer);
    }
}
@After
public void destroy(){
    this.entityTransaction.commit();
    this.entityManager.close();
    this.entityManagerFactory.close();
}
 

Когда я читал вики-книги JPA, в них говорилось: «Это означает, что при вызове persist, слиянии или удалении базы данных ВСТАВКА, ОБНОВЛЕНИЕ, УДАЛЕНИЕ DML не выполняется до фиксации или до запуска сброса».
Но в то же время, когда мой код запускается, я читаю журнал mysql, я нахожу, что каждый раз при постоянном выполнении mysql будет выполнять sql. И я также читаю wireShark, каждый раз будет вызывать запрос к базе данных.
Я помню, что метод jpa saveAll может посылать инструкции SQL в базу данных пакетами? Если я хочу вставить 10000 записей, как повысить эффективность?

Ответ №1:

Мой ответ ниже предполагает, что вы используете Hibernate в качестве реализации jpa. По умолчанию режим гибернации не включает пакетирование. Это означает, что он будет отправлять отдельную инструкцию SQL для каждой операции вставки/обновления.

Вы должны установить hibernate.jdbc.batch_size свойству значение больше 0. Лучше установить это свойство в своем persistence.xml файле, где у вас есть конфигурация jpa, но, поскольку вы не опубликовали его в вопросе, ниже оно задано непосредственно в EntityManagerFactory.

 @Before
public void init() {
    Properties properties = new Properties();
    properties.put("hibernate.jdbc.batch_size", "5");
    this.entityManagerFactory = Persistence.createEntityManagerFactory("jpaLearn", properties);
    this.entityManager = this.entityManagerFactory.createEntityManager();
    this.entityTransaction = this.entityManager.getTransaction();
    this.entityTransaction.begin();
}
 

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

Для дальнейшего чтения, пожалуйста, проверьте: https://www.baeldung.com/jpa-hibernate-batch-insert-update

Комментарии:

1. Я нахожу эти штуки очень хитрыми. Если идентификатор сущности зависит от базы данных(mysql), то мы, возможно, не сможем сохранить пакетирование. Все мои сущности являются новыми объектами, и их идентификаторы зависят от mysql, потому что они являются автоинкрементами.

Ответ №2:

вы должны включить пакетную обработку для спящего режима

 spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
spring.jpa.properties.hibernate.jdbc.batch_size=20
 

и использовать

reWriteBatchedInserts и rewriteBatchedStatements=верно

конец вашей строки подключения