我有2个实体:User
和Player
User
实体与@OneToOne
的关系Player
,Player
与@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个会话
答案 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注释。