我将尝试在JPA事务隔离级别中描述我的问题。

数据库结构:

  • Table1-> PK定义为日期('ddMMyyyy')
  • Table2->使用FK到Table1

  • JPA(隔离级别:: read_commited)-代码:
        Query query = em.createQuery("from Table1 trd where trd.id = :d");
        query.setParameter("d", date);
    
        Table1 t = null;
        try{
            t = (Table1) query.getSingleResult();
        }catch(javax.persistence.NoResultException e){
            t = null;
        }
    
        if(t==null){
            t=new Table1 (date);
            em.persist(trd);
        }
    
        for(Table2 q:tables2){
            q.setTable1(t);
            em.merge(q);
        }
    

    因此,过程将检查该记录是否存在于db中,如果不存在则创建一个新记录。如果系统仅基于一个线程,则方法是完全核心的。否则,可能会出现以下情况:
  • 线程1:检查数据库
  • 中是否存在按日期表示的实体
  • 线程2:做完全相同的

  • 他们俩都认为这样的记录还不存在,因此添加一个新记录。在提交事务之前,一切正常。第一个将毫无异常(exception)地提交,第二个将与主键复制相关的上升异常(exception)提交。

    除了将隔离级别更改为SERIALIZABLE之外,是否有可能保留这种情况?

    最佳答案

    是的,通常隔离级别= SERIALIZABLE应该可以解决您的问题。将隔离级别更改为最严格的选项时,请不要低估副作用。它可能会影响数据库利用率以及请求吞吐量。也许您可以在创建T1之后明确提交TRX,然后打开另一个TRX:
    EntityManager.getTransaction()。commit()

    您仍然必须捕获重复的 key 异常。

    关于java - 交易隔离级别,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6617091/

    10-11 05:01