我将尝试描述JPA事务隔离级别中的问题。
数据库结构:
Table1 -> with PK定义为date ('ddMMyyyy')Table2 -> with FK to Table1JPA(隔离级别::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中,如果没有,则创建新的记录。如果系统只基于一个线程,则该方法是完全编码的。否则,可能会出现这样的情况:
检查database
操作
他们两人都认为这样的记录还没有存在,所以再加上一个新的。在完成交易之前,一切都是正常的。第一项将毫无例外地实行,购买第二项上升例外与主键复制有关。
除了将隔离级别更改为SERIALIZABLE之外,是否有可能保留这种情况?
发布于 2011-07-07 22:00:45
是的,一般来说,隔离级别= SERIALIZABLE应该可以解决您的问题。当将隔离级别更改为最严格的选项时,不要低估副作用。它可能会影响数据库利用率和请求吞吐量。也许您可以在创建T1之后显式提交TRX,然后打开另一个TRX: EntityManager.getTransaction().commit()
您仍然必须捕获重复的键异常。
发布于 2011-07-08 17:48:57
这是数据库在高度并发环境中最难解决的问题之一。最后,唯一真正的解决方案是抓住异常并适当地处理它。
根据您提供的代码,很难判断这可能是什么。如果这是一个webapp,您很可能希望捕获重复的键异常,并向最终用户显示一些有用的消息。比如“这个记录已经创建了”,或者类似的东西。
https://stackoverflow.com/questions/6617091
复制相似问题