Вопрос о Hibernate session.flush()
Я хочу узнать о том, что на самом деле делает метод flush в следующем случае:
for (int i = 0; i < myList.size(); i++) {
Car c = new Car( car.get(i).getId(),car.get(i).getName() );
getCurrentSession().save(c);
if (i % 20 == 0)
getCurrentSession().flush();
}
Означает ли это, что после итерации 20 кеш очищается, а затем 20 сохраненных объектов памяти фактически сохраняются в базе данных?
Может кто-нибудь, пожалуйста, объясните мне, что произойдет, когда условие будет истинным.
Ответы
Ответ 1
Из javadoc Session#flush
:
Принудительный сеанс. Должно быть называемый в конце единицы работы, перед совершением транзакции и закрытие сеанса (в зависимости от флеш-режим, Transaction.commit()вызывает этот метод).
Промывка - это процесс синхронизации основных постоянный магазин с устойчивыми сохраненное в памяти.
Другими словами, flush
сообщает Hibernate выполнить инструкции SQL, необходимые для синхронизации состояния соединения JDBC с состоянием объектов, хранящихся в кеше уровня сеанса. И условие if (i % 20 == 0)
сделает это для каждого i
, кратного 20.
Но, тем не менее, новые экземпляры Car
будут храниться в кеше уровня сеанса, а для больших myList.size()
вы будете есть всю память и, в конечном итоге, получите OutOfMemoryException
. Чтобы избежать этой ситуации, шаблон, описанный в документации, соответствует flush
И clear
сеансу с регулярными интервалами (размер, размер партии JDBC), чтобы сохранить изменения, а затем отсоединить экземпляры так что они могут быть собраны мусором:
При создании новых объектов flush(), а затем очистить() сеанс регулярно, чтобы контролировать размер кеша первого уровня.
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
Customer customer = new Customer(.....);
session.save(customer);
if ( i % 20 == 0 ) { //20, same as the JDBC batch size
//flush a batch of inserts and release memory:
session.flush();
session.clear();
}
}
tx.commit();
session.close();
Документация упоминает в той же главе, как установить размер партии JDBC.
См. также
Ответ 2
Зависит от того, как настроен FlushMode.
В конфигурации по умолчанию Hibernate пытается синхронизировать с базой данных в трех местах.
1. before querying data
2. on commiting a transaction
3. explictly calling flush
Если параметр FlushMode
задан как FlushMode.Manual, программист информирует спящий режим, что он будет обрабатывать, когда передавать данные в базу данных. В этой конфигурации
вызов session.flush()
сохранит экземпляры объектов в базе данных.
A session.clear()
вызов acutally может использоваться для очистки контекста стойкости.
Ответ 3
// Assume List to be of 50
for (int i = 0; i < 50 ; i++) {
Car c = new Car( car.get(i).getId(),car.get(i).getName() );
getCurrentSession().save(c);
// 20 car Objects which are saved in memory syncronizes with DB
if (i % 20 == 0)
getCurrentSession().flush();
}
Несколько указаний относительно того, почему промывка должна соответствовать размеру партии
Чтобы включить пакетную загрузку, вам необходимо установить размер партии jdbc
// In your case
hibernate.jdbc.batch_size =20
Одной из распространенных ошибок при использовании пакетной обработки является то, что если вы используете однообъектное обновление или вставляете, это идет отлично. Но в случае
вы используете множественные объекты, приводящие к нескольким вставкам/обновлениям, тогда вам придется явно установить механизм сортировки.
Например
// Assume List to be of 50
for (int i = 0; i < 50 ; i++) {
Car c = new Car( car.get(i).getId(),car.get(i).getName() );
// Adding accessory also in the card here
Accessories a=new Accessories("I am new one");
c.add(a);
// Now you got two entities to be persisted . car and accessory
// Two SQL inserts
getCurrentSession().save(c);
// 20 car Objects which are saved in memory syncronizes with DB
// Flush here clears the car objects from 1st level JVM cache
if (i % 20 == 0)
getCurrentSession().flush();
getCurrentSession().clear();
}
Здесь в этом случае генерируются два sql 1 для вставки в автомобиль 1 для вставки в аксессуар
Для правильной партии вы должны установить
<prop key="hibernate.order_inserts">true</prop>
чтобы все вставки для автомобиля были отсортированы вместе, и все вставки аксессуаров были отсортированы вместе. При этом у вас будет 20 вставных стрелок в пакетной, а затем 1 кв. стрельбе за раз.
Для разных операций в рамках одной транзакции вы можете посмотреть http://docs.jboss.org/hibernate/core/3.2/api/org/hibernate/event/def/AbstractFlushingEventListener.html
Ответ 4
Да каждые 20 циклов, sql генерируется и выполняется для несохраненных объектов. Также вы должны установить режим партии до 20 для повышения производительности.