事务隔离级别

7

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

数据库结构:

  • Table1 -> 主键定义为日期('ddMMyyyy')
  • Table2 -> 外键指向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:执行完全相同的操作

他们两个都认为这样的记录尚不存在,因此添加新记录。在提交事务之前一切正常。第一个将被提交而没有任何异常,但第二个将引发与主键重复相关的异常。

除了将隔离级别更改为SERIALIZABLE,还有什么办法可以保留这种情况吗?

2个回答

4

一般情况下,隔离级别 = 可串行化 应该可以解决您的问题。但是,不要低估将隔离级别更改为最严格选项时产生的副作用。它可能会影响数据库利用率以及请求吞吐量。也许您可以在创建T1后显式提交TRX,然后打开另一个TRX:

EntityManager.getTransaction().commit()

您仍然需要捕获重复键异常。


2

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

根据您提供的代码很难确定应该采取什么措施。如果这是一个Web应用程序,最可能的是您需要捕获重复键异常并向最终用户显示一些有用的消息。例如“此记录已创建”,或类似的内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接