Для первой версии вашего вопроса вы найдете несколько ответов в главе 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 не выполняет эту оптимизацию (я думаю, это не так просто). Но не стесняйтесь представить патч:)