Когда вы вызываете session.save()
, hibernate сгенерирует INSERT SQL. Этот INSERT SQL будет добавлен для выдачи в БД во время сброса (т.е. session.flush()
).
Во время очистки, если для hibernate.jdbc.batch_size
установлено какое-либо ненулевое значение, Hibernate будет использовать функцию пакетирования, представленную в API JDBC2, для выдачи SQL пакетной вставки в БД.
Например, если вы save()
100 записей, а для hibernate.jdbc.batch_size
установлено значение 50. Во время сброса вместо 100 раз введите следующий SQL:
insert into TableA (id , fields) values (1, 'val1');
insert into TableA (id , fields) values (2, 'val2');
insert into TableA (id , fields) values (3, 'val3');
.........................
insert into TableA (id , fields) values (100, 'val100');
Hiberate сгруппирует их в пакеты по 50 и выдаст только 2 SQL для БД, например:
insert into TableA (id , fields) values (1, 'val1') , (2, 'val2') ,(3, 'val3') ,(4, 'val4') ,......,(50, 'val50')
insert into TableA (id , fields) values (51, 'val51') , (52, 'val52') ,(53, 'val53') ,(54, 'val54'),...... ,(100, 'val100')
Обратите внимание, что Hibernate отключил бы пакетную вставку на уровне JDBC прозрачно, если первичный ключ таблицы вставки - GenerationType.Identity
.
Из вашего журнала: вы save()
только одна запись, а затем flush()
, поэтому для каждого сброса обрабатывается только один добавляемый INSERT SQL. Вот почему Hibernate не может помочь вам выполнить пакетную вставку, так как для обработки требуется только один INSERT SQL. Вы должны save()
до определенного количества записей, прежде чем звонить flush()
вместо того, чтобы звонить flush()
для каждого save()
.
Лучшая практика пакетной вставки выглядит примерно так:
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<888888; i++ ) {
TableA record = new TableA();
record.setXXXX();
session.save(record)
if ( i % 50 == 0 ) { //50, same as the JDBC batch size
//flush a batch of inserts and release memory:
session.flush();
session.clear();
}
}
tx.commit();
session.close();
Вы сохраняете и очищаете записи партии за партией. В конце каждого пакета вы должны очистить контекст постоянства, чтобы освободить часть памяти, чтобы предотвратить исчерпание памяти, так как каждый постоянный объект помещается в кэш первого уровня (память вашей JVM). Вы также можете отключить кэш второго уровня, чтобы уменьшить ненужные издержки.
Справка: