非法尝试将集合与两个打开的会话相关联 - 调用Session.update()时

时间:2015-07-03 15:46:46

标签: java hibernate orm playframework

我有2个实体:UserPlayer

User实体与@OneToOne的关系PlayerPlayer@OneToOne的关系User

出于优化目的,我将User存储在缓存中,并尝试为每个请求检索它们。

因为检索实体(来自缓存)与当前的休眠Session分离,所以我调用当前update()的{​​{1}}方法重新附加它。

为避免错误,我还会检查实体是否已使用Session对象的contains()方法附加到会话。

以下是一个代码示例,向您展示如何继续:

Session

调用此代码以检索已连接的用户。它首先尝试从缓存中检索它。如果用户不在缓存中,我从数据库加载它并将其插入缓存中。然后我更新实体,如果它没有附加,则将它附加到会话。

有时User user = User.getCached(User.class, userId); if (user == null) { user = User.find("from User user left join fetch user.player where user.id = ?", userId).first(); user = User.addToCache(User.class, user); } if (!getSession().contains(user.player)) getSession().update(user.player); // Throws the exception 方法在调用它时抛出以下异常:update()

这是否意味着播放器已经附加到会话中? 如果是,为什么Illegal attempt to associate a collection with two open sessions方法返回false呢? 如果不是,为什么我会得到这个例外?以及如何避免它?

修改

当我收到此异常时,如果我尝试修改我的实体的值并调用contains(),我还有另一个例外,即该实体已分离。如果先前的异常表明它已经与会话相关联,那么它如何分离?

PS:我每个线程只能有1个会话

3 个答案:

答案 0 :(得分:1)

我认为你有一个并发问题:假设有多个并行HTTP请求请求相同的totalDocsExamined。该解决方案将使用一些synchronization

答案 1 :(得分:1)

update 方法有许多缺点:

  • 它总是尝试在使用分离对象时发出更新,否则它无法判断实体分离时是否有某些更改
  • 它可能与已加载的实体副本冲突

这就是merge is a better alternative的原因,因为merge works like this

  • 合并将将分离的实体状态(源)复制到托管实体实例(目标)。如果合并实体在当前会话中没有等效项,则将从数据库中获取一个。即使在合并操作之后,分离的对象实例仍将继续保持分离状态。

所以 merge 操作更加安全,如果实体没有更改,当它被分离时,dirty checking mechanism将阻止不必要的更新。

答案 2 :(得分:0)

1_尝试在检索用户之前清除会话

2_将CascadeType.DETACH添加到@OneToOne注释。