Вопрос о Hibernate session.flush () - PullRequest
28 голосов
/ 18 июля 2010

Я хочу узнать, что на самом деле делает метод 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 сохраненных объектов памяти фактически сохраняются в базе данных?

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

Ответы [ 4 ]

51 голосов
/ 18 июля 2010

Из Javadoc Session#flush:

Принудительно сбросить эту сессию. Должно быть вызывается в конце единицы работы, до совершения сделки и закрытие сессии (в зависимости от flush-mode , Transaction.commit () вызывает этот метод).

Flushing - это процесс синхронизации основных постоянный магазин с постоянным состояние хранится в памяти.

Другими словами, flush говорит Hibernate выполнить SQL-операторы, необходимые для синхронизации состояния соединения JDBC с состоянием объектов, хранящихся в кеше уровня сеанса. И условие if (i % 20 == 0) сделает это для каждого i кратного 20.

Но, тем не менее, новые Car экземпляры будут храниться в кэше уровня сеанса, а для больших myList.size() вы собираетесь съесть всю память и в конечном итоге получить OutOfMemoryException. Чтобы избежать этой ситуации, шаблон, описанный в документации, представляет собой flush И clear сеанс с регулярными интервалами (такой же размер, что и размер пакета JDBC), чтобы сохранить изменения и затем отсоединить экземпляры так, что их можно собрать мусором:

13,1. Пакетные вкладыши

При создании постоянных новых объектов 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 голосов
/ 19 июля 2010

Зависит от того, как настроен FlushMode.

В конфигурации по умолчанию Hibernate пытается синхронизироваться с базой данных в трех местах.

1. before querying data
2. on commiting a transaction
3. explictly calling flush

Если FlushMode установлено как FlushMode.Manual, программист сообщает hibernate, что он / она будет обрабатывать, когда передавать данные в базу данных. Под этой конфигурацией вызов session.flush() сохранит экземпляры объекта в базе данных.

Вызов session.clear() можно использовать для очистки контекста персистентности.

1 голос
/ 18 июля 2010
// 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

0 голосов
/ 18 июля 2010

Да, каждые 20 циклов sql генерируется и выполняется для несохраненных объектов. Вам также следует установить пакетный режим на 20, чтобы увеличить производительность.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...