Spring + Hibernate + DB2 + JTA + XA应用程序中的死锁

应用程序日志中的exception:

12:04:18,503 INFO ExceptionResolver:30 - [ org.springframework.dao.DeadlockLoserDataAccessException ] Hibernate flushing: could not update: [sero.chase.integration.Beans.Bean#1000]; SQL [update SCHM.v***240u_bean set prop1=?, prop2=?, prop3=?, prop4=?, prop5=?, prop6=?, prop7=?, prop8=?, prop9=?, prop10=?, prop11=?, prop12=?, prop13=?, prop14=?, prop15=?, prop16=?, prop17=?, prop18=?, prop19=?, prop20=?, prop21=?, where bean_id=?]; UNSUCCESSFUL EXECUTION CAUSED BY DEADLOCK OR TIMEOUT. REASON CODE 00C90088, TYPE OF RESOURCE 00000302, AND RESOURCE NAME SCHM.SAKT240 .X'000017'. SQLCODE=-913, SQLSTATE=57033, DRIVER=3.53.70; nested exception is com.ibm.db2.jcc.b.SqlException: UNSUCCESSFUL EXECUTION CAUSED BY DEADLOCK OR TIMEOUT. REASON CODE 00C90088, TYPE OF RESOURCE 00000302, AND RESOURCE NAME SCHM.SAKT240 .X'000017'. SQLCODE=-913, SQLSTATE=57033, DRIVER=3.53.70org.springframework.dao.DeadlockLoserDataAccessException: Hibernate flushing: could not update: [sero.chase.integration.Beans.Bean#1000]; SQL [update SCHM.v***240u_bean set prop1=?, prop2=?, prop3=?, prop4=?, prop5=?, prop6=?, prop7=?, prop8=?, prop9=?, prop10=?, prop11=?, prop12=?, prop13=?, prop14=?, prop15=?, prop16=?, prop17=?, prop18=?, prop19=?, prop20=?, prop21=?, where bean_id=?]; UNSUCCESSFUL EXECUTION CAUSED BY DEADLOCK OR TIMEOUT. REASON CODE 00C90088, TYPE OF RESOURCE 00000302, AND RESOURCE NAME SCHM.SAKT240 .X'000017'. SQLCODE=-913, SQLSTATE=57033, DRIVER=3.53.70; nested exception is com.ibm.db2.jcc.b.SqlException: UNSUCCESSFUL EXECUTION CAUSED BY DEADLOCK OR TIMEOUT. REASON CODE 00C90088, TYPE OF RESOURCE 00000302, AND RESOURCE NAME MWIAKT1 .SAKT240 .X'000017'. SQLCODE=-913, SQLSTATE=57033, DRIVER=3.53.70 at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:265) at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72) at org.springframework.orm.hibernate3.HibernateTransactionManager.convertJdbcAccessException(HibernateTransactionManager.java:805) at org.springframework.orm.hibernate3.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:791) at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:664) at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754) at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723) at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) at $Proxy54.save(Unknown Source) at sero.chase.integration.DaoImpl.ExampleDaoImpl.save(ExampleDaoImpl.java:151) at sero.chase.business.BOImpl.ExampleBOImpl.save(ExampleBOImpl.java:191) at sero.chase.ServicesImpl.ExampleServiceImpl.submitAnswer(ExampleServiceImpl.java:183) at sero.chase.business.BusDelegatesImpl.ExampleBusDelegateImpl.gradeAnswer(ExampleBusDelegateImpl.java:578) at sero.chase.presentation.Controller.ExampleController.gradeAnswer(ExampleController.java:326) at sero.chase.presentation.Controller.ExampleController.SubmitAnswer(ExampleController.java:422) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:79) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:618) at org.springframework.web.servlet.mvc.multiaction.MultiActionController.invokeNamedMethod(MultiActionController.java:471) at org.springframework.web.servlet.mvc.multiaction.MultiActionController.handleRequestInternal(MultiActionController.java:408) at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153) at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:900) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:827) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789) at javax.servlet.http.HttpServlet.service(HttpServlet.java:763) at javax.servlet.http.HttpServlet.service(HttpServlet.java:856) at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1152) at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1087) at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:118) at com.ibm.ws.webcontainer.filter.WebAppFilterChain._doFilter(WebAppFilterChain.java:87) at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:840) at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:683) at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:589) at com.ibm.ws.wswebcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:534) at com.ibm.ws.webcontainer.servlet.CacheServletWrapper.handleRequest(CacheServletWrapper.java:90) at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:751) at com.ibm.ws.wswebcontainer.WebContainer.handleRequest(WebContainer.java:1478) at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:126) at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:458) at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewInformation(HttpInboundLink.java:387) at com.ibm.ws.http.channel.inbound.impl.HttpICLReadCallback.complete(HttpICLReadCallback.java:102) at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:165) at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217) at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161) at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:136) at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:196) at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:751) at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:881) at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1497) Caused by: com.ibm.db2.jcc.b.SqlException: UNSUCCESSFUL EXECUTION CAUSED BY DEADLOCK OR TIMEOUT. REASON CODE 00C90088, TYPE OF RESOURCE 00000302, AND RESOURCE NAME MWIAKT1 .SAKT240 .X'000017'. SQLCODE=-913, SQLSTATE=57033, DRIVER=3.53.70 at com.ibm.db2.jcc.b.bd.a(bd.java:679) at com.ibm.db2.jcc.b.bd.a(bd.java:60) at com.ibm.db2.jcc.b.bd.a(bd.java:127) at com.ibm.db2.jcc.b.fm.b(fm.java:2132) at com.ibm.db2.jcc.b.fm.c(fm.java:2115) at com.ibm.db2.jcc.t4.db.k(db.java:353) at com.ibm.db2.jcc.t4.db.a(db.java:59) at com.ibm.db2.jcc.t4.ta(t.java:50) at com.ibm.db2.jcc.t4.tb.b(tb.java:200) at com.ibm.db2.jcc.b.gm.Zb(gm.java:2445) at com.ibm.db2.jcc.b.gm.e(gm.java:3287) at com.ibm.db2.jcc.b.gm.Rb(gm.java:612) at com.ibm.db2.jcc.b.gm.executeUpdate(gm.java:595) at com.ibm.ws.rsadapter.jdbc.WSJdbcPreparedStatement.executeUpdate(WSJdbcPreparedStatement.java:768) at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:23) at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2399) at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2303) at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2603) at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:92) at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248) at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:232) at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:140) at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298) at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27) at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000) at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338) at org.hibernate.transaction.JTATransaction.commit(JTATransaction.java:135) at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656) ... 50 more 

弹簧配置:

                                                /WEB-INF/tiles-def.xml                              PROPAGATION_REQUIRED                        

Hibernate非XA配置:

    sero.chase.integration.Hibernate.DB2390Dialect  SCHM yes 'Y', no 'N' true true true org.hibernate.transaction.JTATransactionFactory java:comp/UserTransaction  org.hibernate.cache.EhCacheProvider        

Hibernate XA配置:

    sero.chase.integration.Hibernate.DB2390Dialect  SCHMA yes 'Y', no 'N' true true true org.hibernate.transaction.CMTTransactionFactory  org.hibernate.transaction.WebSphereExtendedJTATransactionLookup  org.hibernate.cache.EhCacheProvider        

我的服务实现类中的代码片段,其中发生了大多数业务逻辑:

 public void someDeadlockCausingServiceMethod() { //The read1() method below is going to executing a select hql statement on Table A once the call goes all the way down to the Dao layer. List beanList = exampleBO.read1(); //Do some processing with the values obtained from the read1() method ... // //saveOrUpdate() method below is going to execute an update hql statement on Table A once the call goes all the way down to the Dao layer //where the values from someBeanInBusinessLayer is going to be copied into someBeanInDaoLayer before saving. exampleBO.saveOrUpdate(someBeanInBusinessLayer) //The read2() method below is going to execute a select hql statement that contains two inner selects (on Table B, C and D) once the call goes all //the way down to the Dao layer. List beanList2 = exampleBO.read2(); //Do some processing with the values obtained from the read2() method inside a for loop for(SomeBeanInBusinessLayer2 s: beanList2) { //Read values from table E List beanList3 = exampleBO.read3(s.getProp2()); SomeBeanInBusinessLayer2 someBeanInBusinessLayer2 = new SomeBeanInBusinessLayer2(); someBeanInBusinessLayer2.setProp1(s.getProp2()); someBeanInBusinessLayer2.setProp1(someBeanInBusinessLayer3.getProp2()); //... more processing... //Below method will execute an insert hql on Table F exampleBO.saveOrUpdate(someBeanInBusinessLayer2); SomeBeanInBusinessLayer3 someBeanInBusinessLayer3 = new SomeBeanInBusinessLayer3(); someBeanInBusinessLayer3.setProp1(s.getProp5()); //... more processing... //Below method will execute an insert hql on Table G exampleBO.saveOrUpdate(someBeanInBusinessLayer3); } } public void anotherDeadlockCausingServiceMethod() { //The read1() method below is going to executing a select hql statement on Table A once the call goes all the way down to the Dao layer. List beanList = exampleBO.read1(); //The read2() method below is going to executing a select hql statement on Table F once the call goes all the way down to the Dao layer. List beanList2 = exampleBO.read2(); //The read1() method below is going to executing a select hql statement on Table G once the call goes all the way down to the Dao layer. List beanList3 = exampleBO.read3(); //Do some processing with the values obtained... //Do an update on Table A exampleBO.saveOrUpdate(someBeanInBusinessLayer1) //Do an update on Table F exampleBO.saveOrUpdate(someBeanInBusinessLayer2) } 

我的Dao layer1的代码片段:

 public void load(BeanDTO beanDTO) { Object param1 = beanDTO.getBeanList().getProp1(); Object param2 = beanDTO.getBeanList().getProp2(); List beanList = null; Object[] params = {param1, param2}; UserTransaction ut = null; try { Context context = new InitialContext(); ut = (UserTransaction) context.lookup(Constant.USR_TRANSACTION); ut.begin(); beanList = beanDao2.load(params); ut.commit(); } catch(Exception e) { try { ut.rollback(); } catch(Exception e1) { if(logger.isDebugEnabled()) { logger.debug("DB Exception", e1); } } int error = ExceptionResolver.resolve(e); if(logger.isDebugEnabled()) { logger.debug("DB Exception", e); } beanDTO.setErrorCode(error); } beanDTO.setBeanList(beanList); } public void save(BeanDTO beanDTO) { List beanList = beanDTO.getBeanList(); for(SomeBeanInDaoLayer bean: beanList) { try { Context context = new InitialContext(); ut = (UserTransaction) context.lookup(Constant.USR_TRANSACTION); ut.begin(); beanDao2.save(bean); ut.commit(); } catch(Exception e) { try { ut.rollback(); } catch(Exception e1) { if(logger.isDebugEnabled()) { logger.debug("DB Exception", e1); } } int err = ExceptionResolver.resolve(e); if(logger.isInfoEnabled()) { logger.info("DB Exception", e); } beanDTO.setErrorCode(err); } } } 

我的Dao Layer2中的代码片段:

 public List load(Object[] params) { String hql = "from Bean where beanProp1 = ? and beanProp2 = ?"; return (List) getHibernateTemplate().find(hql, params); } public void save(Bean bean) { getHibernateTemplate().saveOrUpdate(bean); } 
  1. 该应用程序是一个测试系统,用户可以同时进行测试。
  2. 最初,事务划分不在我的Dao层,而是在我的Service Implementation类(实际上一直在我的控制器类中)说,其中几个读取和更新被绑定到begin-commit块中的一个事务中。 因为我看到了几个死锁,所以我将划分移到Dao层,这样我的begin-commit块之间只有一个hql语句,看看它是否能阻止死锁,但却没有运气。
  3. 尝试将hibernate.connection.autocommit等设置属性设置为true,将hibernate.transaction.flush_before_completion设置为true,将hibehibernate.transaction.auto_close_session设置为true,但没有运气。
  4. 一个用户读取的行不会被另一个用户更新。 每个用户即使访问相同的DB2表,也会读取和更新不同的行。 只有在运行构建测试问题集的过程时,如果用户采用相同类型的测试,则会读取相同的行。 它与上面描述的someDeadlockCausingMethod非常相似,其中测试问题是从包含问题和答案的一组表中准备的。 通过在for循环中迭代此结果集,将新行插入到另一个表中以保存将出现在用户测试中的每个问题的详细信息。 此步骤在应用程序中是必需的,因为即使两个用户进行相同的测试,也会从每个用户的所有问题池中获取一组随机问题。
  5. 现在测试是为用户进行测试而准备的,应用程序的下一个逻辑步骤是从表中读取行,其中只包含与参加测试的用户有关的问题的详细信息。 因此,并发用户在此过程中会读取同一个表,但从不会读取同一行。 一次向用户呈现一个问题。 用户回答问题后,将使用答案选项更新为了获得与此用户相关的问题而读取的行。 同样,两个并发用户永远不会更新相同的行。 此方法类似于上面描述的anotherDeadlockCausingMethod()。
  6. 我希望你知道应用程序的function。 并发用户从不读取或更新相同行的事实让我对资源如何被锁定感到惊讶。 然后我发现页面锁定已经到位,表格会更新。 所以我去问DBA他是否可以将其更改为对已更新的表进行行锁定。 他担心DB2实现行锁定的性能开销,并担心它是否会影响使用DB2的其他应用程序。 所以他不想这样做,除非我找不到任何其他解决方案。
  7. 请忘记XA / JMS部分。 假设该部分暂时被注释掉。 对于应用程序的大部分内容,在我看到死锁的地方使用非XA数据源。

    有人可以告诉我如何解决僵局? 我想了解设计中出了什么问题。 任何帮助都提前非常感谢

当你执行几个插入,更新,删除我想建议你添加

  

一旦所有查询成功执行,然后手动提交connection.commit(); 也许这可以帮到你。

最后我管理了一个没有死锁的干净运行,执行以下操作:

  1. hibernate.connection.isolation = 2
  2. 在我的select语句末尾添加了’with cs’更新。
  3. 我正在使用saveOrUpdate()hibernate方法进行更新和插入。 现在我使用save()进行插入,使用update()进行更新。

我不明白的一件事是,为什么在我的select语句结束时使用’with ur’并没有解决与我现在使用的’with cs’相比的死锁问题。 想知道有数据库的隔离级别,这是’rs’必须做什么吗?