java Hibernate和修改同一实体的线程
我在不同的线程中使用相同的实体,并收到一个optimisticlockexception
。我认为在我的情况下,必须避免这种例外情况。情况如下:
我的A级成绩如下:
public class A{
List<B> b;
List<C> c;
public void addinListB(B elem){
b.add(elem);
}
public void addinListC(C elem){
c.add(elem);
}
}
然后,我有一个使用和修改类的对象类。 目标是:
public class SomeObject {
private static final Object lock = new Object();
public A search( String idA ){
synchronized (lock) {
A a = null;
try{
a = (A) getPersistenceContext()
.createQuery("from A where "+ id = :id ")
.setParameter("id", id).getSingleResult();
}catch (NoResultException e) {
A = new A();
getPersistenceContext().persist(bday);
getPersistenceContext().flush();
}
}
return a;
}
}
@Transactional
public someMethodB(){
A a = search(1);
B b = new B();
a.addBinListB(B);
}
@Transactional
public someMethodC(){
A a = search(1);
C c = new c();
a.addCinListC(c);
}
}
因此,问题如下:
我们有两个命令同时运行,一个正在执行“someMethodB(1)”,另一个正在执行“someMethodC(1)”,寻找相同的A id。
假设:id=1的A不存在:
这意味着第一个赢得锁的人将创建一个实例,另一个将使用它。导致在两个线程中同时修改相同的ATATATCH obejct。因此,当第一个线程提交事务时,刷新完成,但当第二个线程提交时,抛出一个optimisticlockexception
在这种情况下可以避免optimisticlockexception
吗?我了解到A对象正在“修改”添加两个不同的对象(B和C),但我们可以意识到A对象是数据库中的一个对象,只有两个线程在指向A的不同表中添加新对象
有没有办法同时修改A实体(向A添加几个B和C对象)并避免optimisticlockexception
问候
# 1 楼答案
Hibernate有一个没有被广泛记录的选项,在这个选项中,只要不修改相同的字段,就可以同时修改相同的实体,保持隔离。当然,这可能与业务语义相冲突,所以在采用它时必须非常小心。由于您在一个系统中修改不同的集合,我想这符合您的情况
乐观锁=‘脏’
你是怎么做到的?这不是JPA标准,所以你必须使用hibernate@Entity注释并添加属性optimisticLock='dirty'
请参见Hibernate docs、redhat,以及this link对其进行了解释(尽管它使用xml配置,但效果相同)
使用风险自负
# 2 楼答案
每个线程都应该有自己的entityManager实例,您应该让容器(如果有)注入entityManager实例(@PersistenceContext),或者在ThreadLocal中存储一个专用实例
见How to make DB access with Hibernate JPA thread-safe?