2011-07-07 132 views
6

我会尽力描述JPA的事务隔离级别我的问题。事务隔离级别

数据库结构:

  • Table1 - >与PK定义为日期( 'DDMMYYYY')
  • Table2 - >与FK到Table 1

JPA(隔离级别:: read_commited) - code:

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

So procedu重新检查记录是否存在于数据库中,如果没有创建新记录。如果系统基于一个线程,方法是完全相同的。否则,有可能发生的情况是这样的:

  • 主题1:检查实体代表按日期数据库中存在
  • 线程2:做同样的

他们都认为这样的记录有不存在,所以添加一个新的。一切正常,直到提交交易的时刻。没有任何异常第一个将被COMMITED,购买与主键复制相关的第二个上升例外。

是任何可能保留这样的情况下,只是将隔离级别设置为SERIALIZABLE

回答

3

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

你仍然需要捕获重复密钥异常。

1

这是在高度并发环境中解决数据库最困难的问题之一。最后,你唯一真正的解决办法是捕捉异常,并用它妥善处理。

根据您提供的代码很难说出可能的结果。如果这是一个web应用程序,那么很可能您希望捕获重复的键例外情况并向最终用户显示一些有用的消息。如“这个记录已经创建”,或者沿着这些线。