новичок hibernate кеш первого уровня путаница - PullRequest
2 голосов
/ 27 мая 2010

Я только вхожу в спящий режим. Немного смущен.

Я просто хотел посмотреть, как работает кэш первого уровня, который, как я понял, позволяет группировать запросы до конца сеанса.

Но если я создаю объект, hibernate сразу сохраняет его, поэтому, когда я позже обновляю его в той же транзакции, он также должен выполнить обновление:

Session session = factory.getCurrentSession();
session.beginTransaction();

Test1 test1 = new Test1();
test1.setName("Test 1");
test1.setValue(10);
// Touch it
session.save(test1);

System.out.println("At checkpoint 1");

test1.setValue(20);

session.getTransaction().commit();

Я вижу sql для сохранения, затем «На контрольной точке 1», затем sql для обновления. У меня что-то настроено неправильно или я неправильно понимаю кэш первого уровня hibernate? Есть ли хороший документ в кэше первого уровня - я ничего не нашел в документах гибернации, но я мог бы легко его пропустить ..

Спасибо!

1 Ответ

2 голосов
/ 27 мая 2010

Для первой версии вашего вопроса вы найдете несколько ответов в главе 10.2. Оформление объектов из документации:

Вновь созданные экземпляры постоянный класс считаются переходный по Hibernate. Мы можем сделать временный экземпляр, постоянный связать это с сеансом:

DomesticCat fritz = new DomesticCat();
fritz.setColor(Color.GINGER);
fritz.setSex('M');
fritz.setName("Fritz");
Long generatedId = (Long) sess.save(fritz);

Если Cat имеет сгенерированный идентификатор, идентификатор генерируется и присваивается cat, когда save() называется. Если Cat имеет назначенный идентификатор или составной ключ, идентификатор должен быть присвоен cat экземпляр перед вызовом save(). Вы также можете использовать persist() вместо save(), с семантика определена в EJB3 рано проект.

  • persist() делает временный экземпляр постоянным. Тем не менее, это делает не гарантирует, что идентификатор значение будет присвоено постоянный экземпляр немедленно, назначение может произойти во время сброса. persist() также гарантирует, что это не выполнит оператор INSERT если он вызывается вне транзакции границы. Это полезно в длительные разговоры с расширенный контекст сеанса / постоянства.
  • save() гарантирует возврат идентификатора. Если INSERT должен быть выполняется для получения идентификатора (например, генератор «идентичности», а не «последовательность»), это INSERT происходит немедленно , независимо от того, находитесь ли вы внутри или снаружи транзакции. Это проблематично в длительном разговоре с расширенный контекст сеанса / постоянства.

Кстати, если вы внимательно посмотрите на метод save(), вы заметите, что он действительно возвращает Serializable (назначенный идентификатор).


Теперь, что касается обновленной версии вашего вопроса, Hibernates использует ActionQueue, что содержит операции DML, поставленные в очередь как часть семантики транзакционной записи с обратной записью сеанса. Операции DML ставятся здесь в очередь, пока очистка не заставит их выполняться над базой данных.

Когда вы вызываете save() или persist(), действие вставки , которое содержит копию значений сущности, которая будет вставлена, добавляется в список «вставок».

Затем вы изменяете постоянную сущность, и во время сброса сущность определяется как грязная, и для этой же сущности добавляется другое действие ( действие обновления ) с другой копией значений этой сущности: ожидающее действие вставки не обновляется с новыми значениями.

И это приводит к двум операциям DML (INSERT и UPDATE).

Такое поведение как-то объясняется в комментариях ЧЧХ-2588 . Это (конечно) не оптимально, но именно так работает текущая реализация Hibernate, и я не знаю всех деталей, чтобы объяснить, почему Hibernate не выполняет эту оптимизацию (я думаю, это не так просто). Но не стесняйтесь представить патч:)

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