我正在努力理解Session.persist()的语义,以及实体管理器对未保存的瞬态实例所做的确切操作。我想要实现的只是在会话中添加一个新的临时实例,并在会话刷新时让Hibernate执行一个INSERT。
我已经发现,如果一个新实例被持久化,然后在同一会话中进行修改,那么实体管理器将生成INSERT和UPDATE语句,这可能导致违反约束。
例如,假设我有一个实体关系Foo,它有一个NOT NULL列栏和下面的服务方法。
@Transactional
void persistFoo(String bar) {
Foo foo = new Foo();
session.persist(foo);
foo.setBar(bar);
}尽管我们为bar提供了一个值,但是执行此代码将违反数据库中的NULL约束。
BatchUpdateException: Cannot insert the value NULL into column 'bar'Hibernate文档声明如下。
持久化()使瞬态实例持久。但是,它并不保证标识符值将立即分配给持久实例,分配可能发生在刷新时.
INSERT确实是在事务块末尾刷新会话时执行的,但它仍然使用来自对象的属性值进行参数化,就像调用persist()时一样。
我知道这个例子说明的特定问题可以通过一些简单的更改来解决,但我更感兴趣的是尝试理解它应该如何工作。
我的问题是,这种行为只是Session.persist()合同的一部分,还是可以改变?如果是这样的话,我如何让会话将生成的INSERT语句的参数收集推迟到实际执行时?
发布于 2015-05-26 15:07:28
是的,这是Session.persist()合同的一部分。根据Hibernate文档,这是SQL执行的顺序:
这个顺序是官方Hibernate API的一部分,应用程序在操作它们的实体图时依赖它。
将Session.persist()之后发生的更改立即放到INSERT语句中,会破坏这个契约,并会在某些用例中造成问题。
假设我们有一个User实体,并且有可能两个用户以某种方式相互关联。然后,我们可以将两者插入到一个事务中:
persist(user1);
persist(user2);
user1.setPartner(user2);
user2.setPartner(user1);如果所有内容都存储在INSERT语句中,那么在持久化user1时,就会出现外键约束冲突。
通常,通过确保只传递给persist的状态在INSERT中结束,Hibernate为我们提供了更多满足底层DB约束的灵活性。
我不知道可以用什么配置来改变这种行为。当然,正如您提到的,您可以重构代码,以便在设置所有值之后调用persist,前提是不违反DB约束。
https://stackoverflow.com/questions/30307437
复制相似问题