首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >正确使用Session.persist()

正确使用Session.persist()
EN

Stack Overflow用户
提问于 2015-05-18 15:38:55
回答 1查看 836关注 0票数 3

我正在努力理解Session.persist()的语义,以及实体管理器对未保存的瞬态实例所做的确切操作。我想要实现的只是在会话中添加一个新的临时实例,并在会话刷新时让Hibernate执行一个INSERT

我已经发现,如果一个新实例被持久化,然后在同一会话中进行修改,那么实体管理器将生成INSERTUPDATE语句,这可能导致违反约束。

例如,假设我有一个实体关系Foo,它有一个NOT NULL列栏和下面的服务方法。

代码语言:javascript
复制
@Transactional
void persistFoo(String bar) {
    Foo foo = new Foo();
    session.persist(foo);
    foo.setBar(bar);
}

尽管我们为bar提供了一个值,但是执行此代码将违反数据库中的NULL约束。

代码语言:javascript
复制
BatchUpdateException: Cannot insert the value NULL into column 'bar'

Hibernate文档声明如下。

持久化()使瞬态实例持久。但是,它并不保证标识符值将立即分配给持久实例,分配可能发生在刷新时.

INSERT确实是在事务块末尾刷新会话时执行的,但它仍然使用来自对象的属性值进行参数化,就像调用persist()时一样。

我知道这个例子说明的特定问题可以通过一些简单的更改来解决,但我更感兴趣的是尝试理解它应该如何工作。

我的问题是,这种行为只是Session.persist()合同的一部分,还是可以改变?如果是这样的话,我如何让会话将生成的INSERT语句的参数收集推迟到实际执行时?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-05-26 15:07:28

是的,这是Session.persist()合同的一部分。根据Hibernate文档,这是SQL执行的顺序:

  1. 插入,按执行顺序排列。
  2. 更新
  3. 删除集合元素
  4. 插入集合元素
  5. 按执行顺序删除

这个顺序是官方Hibernate API的一部分,应用程序在操作它们的实体图时依赖它。

Session.persist()之后发生的更改立即放到INSERT语句中,会破坏这个契约,并会在某些用例中造成问题。

假设我们有一个User实体,并且有可能两个用户以某种方式相互关联。然后,我们可以将两者插入到一个事务中:

代码语言:javascript
复制
persist(user1);
persist(user2);
user1.setPartner(user2);
user2.setPartner(user1);

如果所有内容都存储在INSERT语句中,那么在持久化user1时,就会出现外键约束冲突。

通常,通过确保只传递给persist的状态在INSERT中结束,Hibernate为我们提供了更多满足底层DB约束的灵活性。

我不知道可以用什么配置来改变这种行为。当然,正如您提到的,您可以重构代码,以便在设置所有值之后调用persist,前提是不违反DB约束。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30307437

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档