Java 休眠和线程修改同一实体

Java 休眠和线程修改同一实体,java,multithreading,hibernate,jpa,Java,Multithreading,Hibernate,Jpa,我在不同的线程中使用相同的实体,我收到一个optimisticlockexception。我认为在我的情况下,必须避免这种例外情况。情况如下: 我的A级成绩如下: public class A{ List<B> b; List<C> c; public void addinListB(B elem){ b.add(elem); } public void addinListC(C elem

我在不同的线程中使用相同的实体,我收到一个
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);
    }

}
因此,问题如下: 我们有两个命令同时运行,一个正在执行“someMethodB(1)”,另一个正在执行“someMethodC(1)”,寻找相同的A id。 假设:id=1的A不存在: 这意味着第一个赢得锁的人将创建一个实例,另一个将使用它。导致在两个线程中同时修改相同的ATATATCH obejct。因此,当第一个线程提交事务时,刷新完成,但当第二个线程提交时,将抛出一个
optimisticlockexception

在这种情况下,是否可以避免出现
optimisticlockexception
?我了解到A对象正在“修改”添加两个不同的对象(B和C),但我们可以意识到A对象是数据库中的一个对象,只有两个线程在指向A的不同表中添加新对象

是否有任何方法可以同时修改A实体(向A添加多个B和C对象)并避免出现
optimisticlockexception


关于

Hibernate有一个未被广泛记录的选项,在该选项中,只要不修改相同的字段,就可以同时修改相同的实体以保持隔离。当然,这可能与业务语义相冲突,因此在采用它时必须非常小心。由于您正在一个系统中修改不同的集合,我想这符合您的情况

乐观锁='Dirty'

如何启用它?这不是JPA标准,因此您必须使用hibernate@Entity注释并添加属性optimisticLock='dirty'

请参阅,这也解释了它(虽然它使用xml配置-但效果相同)


使用风险自负

每个线程都应该有自己的entityManager实例,您应该让容器(如果有)注入entityManager实例(@PersistenceContext),或者在ThreadLocal中存储一个专用实例

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);
    }
}