【问题标题】:Hibernate: Safely reattach an object to the session休眠:安全地将对象重新附加到会话
【发布时间】:2011-02-13 09:29:47
【问题描述】:

我通过在地图中存储(可能是分离的)对象来维护跨休眠会话的对象缓存。当缓存被命中时,我测试该对象是否已经是与Session.contains(object) 的会话的一部分。如果没有,我用Session.lock(object, LockMode.NONE) 重新附加它。

问题是,如果之前在会话中加载了相同的对象,它会抛出 org.hibernate.NonUniqueObjectException。给定一个分离的实例,我认为没有办法提前找出是否会引发此异常,而不会影响数据库。

有几种解决方法:

  1. 在每个事务开始时重新附加所有缓存的对象。
  2. 捕获 NonUniqueObjectException 然后调用 session.load(object.class, object.getId());

这些都不像提前检查会话中的对象类 + id 那样干净。

有没有办法做到这一点?

【问题讨论】:

标签: java hibernate


【解决方案1】:

Session.merge() 应该这样做:

obj = session.merge(obj);

【讨论】:

  • 我认为 merge() 会命中数据库,这是我希望避免的。请注意, session.lock(detached_object, LockMode.NONE) 根本不会命中数据库(如果您在重新附加后不更改它)
【解决方案2】:

我正在跨休眠会话维护对象缓存

不是直接的答案,但您为什么不为此使用 Hibernate L2 缓存而不是重新发明轮子?

【讨论】:

  • 我认为 L2 缓存在这里没有帮助,因为我不知道持久实体的 id ——我使用 .equals() 查找缓存中的实体,因此它有效地替换了具有已存在的等效实体的新实体。这是数据库的一种享元模式。不幸的是,这对我的应用程序来说是必要的,因为在创建新实体时可以重复使用大量不可变数据。
  • @Rob 好的,我明白了……除了“我不知道 id”部分。这些对象是参考数据(例如,国家、货币等)吗?
  • 是的,它们是价值对象,其身份并不重要。它们只是实体,因此可以共享它们的引用。这使我可以重用来自数百万其他人的相同的 64kb blob。它们不是像国家、货币等那样的标准,但它是相同的想法。
  • @Rob:在您的情况下,您有非可变(只读)实体,对吗?无论如何,没有什么能阻止您拥有合成的Entity.getId() { return this; },因此该实体将充当其自身的 ID。它应该实现Serializableequals()hashCode()。但是,我认为,所有持久实体都应该有一个密钥(货币代码、国家代码)。也许您可以为这些实体设置自定义实体持久化器,然后您可以控制它们的 ID。也许使用 Session 拦截器会有所帮助。
猜你喜欢
  • 1970-01-01
  • 2013-12-07
  • 2015-04-11
  • 1970-01-01
  • 2015-06-12
  • 1970-01-01
  • 2018-01-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多