【问题标题】:Transaction Isolation Level事务隔离级别
【发布时间】:2011-09-30 19:39:32
【问题描述】:

我将尝试在 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);
    }

所以程序检查数据库中是否存在记录,如果不存在则创建新记录。如果系统仅基于一个线程,则方法是完全正确的。否则可能会出现这样的情况:

  • 线程 1:检查数据库中是否存在按日期表示的实体
  • 线程 2:完全相同

他们都认为这样的记录还不存在,所以添加一个新的。在提交交易之前一切正常。第一个会无异常commit,第二个是主键重复相关的异常。

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

【问题讨论】:

    标签: java database hibernate jpa transactions


    【解决方案1】:

    这是在高并发环境中使用数据库最难解决的问题之一。最后,您唯一真正的解决方案是捕获异常并适当地处理它。

    根据您提供的代码,很难判断这可能是什么。如果这是一个 web 应用程序,您很可能希望捕获重复键异常并向最终用户显示一些有用的消息。例如“此记录已创建”或类似的内容。

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        猜你喜欢
        • 2015-07-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-27
        • 2020-06-07
        • 2010-11-05
        • 2017-07-06
        相关资源
        最近更新 更多