Тупик в приложении Spring+Hibernate+DB2+JTA+XA
Исключение из журнала приложений:
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.t.a(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
Конфигурация пружины:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
<jee:jndi-lookup id="queueConFac" resource-ref="true" jndi-name="jms/queueConFac" />
<jee:jndi-lookup id="receiveQ" resource-ref="true" jndi-name="jms/receiveQ" />
<jee:jndi-lookup id="sendQ" resource-ref="true" jndi-name="jms/sendQ" />
<jee:jndi-lookup id="XA" resource-ref="true" jndi-name="jdbc/XA" />
<jee:jndi-lookup id="nonXA" resource-ref="true" jndi-name="jdbc/nonXA" />
<bean id="jmsTxManager"
class="org.springframework.transaction.jta.WebSphereUowTransactionManager"/>
<bean id="jmsDestResolver" class=" org.springframework.jms.support.destination.JndiDestinationResolver"/>
<bean id="exampleListener" class="sero.chase.integration.JMS.Services.JMSReceiver">
<property name="exampleAppBusDelegate" ref="exampleAppBusDelegate" />
</bean>
<bean class="org.springframework.jms.listener.DefaultMessageListenerContainer" >
<property name="connectionFactory" ref="queueConFac" />
<property name="destination" ref="receiveQ" />
<property name="messageListener" ref="exampleListener" />
<property name="transactionManager" ref="jmsTxManager" />
<property name="taskExecutor" ref="jmsTaskExecutor" />
</bean>
<bean id="jmsTaskExecutor"
class="org.springframework.scheduling.commonj.WorkManagerTaskExecutor">
<property name="workManagerName" value="wm/default" />
</bean>
<bean id="jmsSender" class="sero.chase.integration.JMS.Services.JMSSender">
<property name="connectionFactory" ref="queueConFac" />
<property name="queue" ref="sendQ" />
</bean>
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="en" />
</bean>
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="language" />
</bean>
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" >
<property name="interceptors">
<list>
<ref bean="localeChangeInterceptor" />
</list>
</property>
</bean>
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="WEB-INF/resources/langSpecificText"/>
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.tiles2.TilesView" />
</bean>
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles-def.xml</value>
</list>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/nonXA" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="nonXA" />
<property name="configLocation" value="classpath:/hibernate.cfg.nonXA.xml" />
<property name="entityInterceptor">
<bean class="sero.chase.integration.Hibernate.DB2Interceptor"/>
</property>
</bean>
<bean id="session.XA.Factory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="XA" />
<property name="configLocation" value="classpath:/hibernate.cfg.XA.xml" />
<property name="entityInterceptor">
<bean class="sero.chase.integration.Hibernate.DB2Interceptor"/>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="transaction.XA.Manager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="session.XA.Factory" />
</bean>
<bean id="transactionAttributeSource"
class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource">
<property name="properties">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!-- App Bean Definitions (Two dao configurations excluding several other bean configurations are displayed below) -->
<bean id="exampleDao"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
lazy-init="true">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributeSource" ref="transactionAttributeSource" />
<property name="target">
<bean class="sero.chase.integration.PersistenceImpl.ExamplePersistenceImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</property>
</bean>
<bean id="exampleXADao"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
lazy-init="true">
<property name="transactionManager" ref="transaction.XA.Manager" />
<property name="transactionAttributeSource" ref="transactionAttributeSource" />
<property name="target">
<bean class="sero.chase.integration.PersistenceImpl.ExamplePersistenceImpl">
<property name="sessionFactory" ref="session.XA.Factory" />
</bean>
</property>
</bean>
</beans>
Конфигурация Hibernate Non XA:
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">
sero.chase.integration.Hibernate.DB2390Dialect
</property>
<property name="hibernate.default_schema">SCHM</property>
<property name="query.substitutions">yes 'Y', no 'N'</property>
<property name="jdbc.use_streams_for_binary">true</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
<property name="jta.UserTransaction">java:comp/UserTransaction</property>
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
<!--===============-->
<!-- mapping files -->
<!--===============-->
<mapping resource="sero/chase/integration/hbm/Example.hbm.xml" />
</session-factory>
</hibernate-configuration>
Конфигурация Hibernate XA:
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">
sero.chase.integration.Hibernate.DB2390Dialect
</property>
<property name="hibernate.default_schema">SCHMA</property>
<property name="query.substitutions">yes 'Y', no 'N'</property>
<property name="jdbc.use_streams_for_binary">true</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.CMTTransactionFactory </property>
<property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</property>
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
<!--===============-->
<!-- mapping files -->
<!--===============-->
<mapping resource="sero/chase/integration/hbm/Example.hbm.xml" />
</session-factory>
</hibernate-configuration>
Фрагмент кода из моего класса реализации сервиса, где происходит большая часть бизнес-логики:
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<SomeBeanInBusinessLayer> 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<SomeBeanInBusinessLayer2> 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<SomeBeanInBusinessLayer3> 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<SomeBeanInBusinessLayer> 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<SomeBeanInBusinessLayer2> 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<SomeBeanInBusinessLayer3> 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<SomeBeanInDaoLayer> 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<SomeBeanInDaoLayer> 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<Bean> load(Object[] params) {
String hql = "from Bean where beanProp1 = ? and beanProp2 = ?";
return (List<Bean>) getHibernateTemplate().find(hql, params);
}
public void save(Bean bean) {
getHibernateTemplate().saveOrUpdate(bean);
}
- Это приложение представляет собой систему тестирования, где пользователи могут проходить тестирование одновременно.
- Первоначально разграничение транзакций происходило не на моем уровне Dao, а, скажем, на моем классе реализации сервиса (фактически, полностью на уровне моего контроллера), где несколько операций чтения и обновления были связаны в одну транзакцию в пределах блока begin-commit. Поскольку я видел несколько взаимоблокировок, я переместил демаркацию на слой Dao, чтобы между моим блоком begin-commit была только одна инструкция hql, чтобы увидеть, предотвращает ли она взаимоблокировку, но не повезло.
- Попытался установить для свойств, таких как hibernate.connection.autocommit значение true, для hibernate.transaction.flush_before_completion значение true, а hibehibernate.transaction.auto_close_session - значение true, но не повезло.
- Никогда строка, прочитанная одним пользователем, не обновляется другим пользователем. Каждый пользователь читает и обновляет разные строки, даже если они обращаются к одним и тем же таблицам DB2. Только во время запуска процесса создания набора вопросов для теста два пользователя будут читать одни и те же строки, если они будут проходить один и тот же тип теста. Он очень похож на описанный выше метод someDeadlockCausingMetho, где тестовые вопросы готовятся из набора таблиц, содержащих вопросы и ответы. После итерации по этому результирующему набору внутри цикла for новые строки вставляются в другую таблицу, чтобы сохранить детали каждого вопроса, который появится в тесте пользователя. Этот шаг необходим в приложении, поскольку, хотя два пользователя сдают один и тот же тест, набор случайных вопросов берется из пула всех вопросов для каждого пользователя.
- Теперь, когда тест подготовлен для того, чтобы пользователь прошел тест, следующим логическим шагом в приложении является чтение строк из таблицы, которые содержат только детали вопросов, относящихся к пользователю, проходящему тест. Таким образом, параллельный пользователь будет читать одну и ту же таблицу во время этого процесса, но не одну и ту же строку Пользователю предоставляется один вопрос за раз. Как только пользователь отвечает на вопрос, строка, которая была прочитана, чтобы получить вопрос, относящийся только к этому пользователю, будет обновлена с выбором ответа. Снова никогда не обновляются одинаковые строки для двух одновременно работающих пользователей. Этот метод аналогичен другому описанному выше DedelockCausingMethod().
- Я надеюсь, что вы поняли, что делает приложение. Тот факт, что параллельные пользователи никогда не читают и не обновляют одни и те же строки, удивил меня, как ресурс может быть заблокирован. Затем я понял, что для обновления таблиц была установлена блокировка страниц. Поэтому я пошел и спросил администратора базы данных, может ли он изменить его на блокировку строк в обновляемых таблицах. Он обеспокоен повышением производительности в DB2 для реализации блокировки строк и обеспокоен, может ли это повлиять на другие приложения, использующие DB2. Поэтому он не хочет этого делать, если я не найду другого решения.
- Пожалуйста, забудьте часть XA/JMS. Предположим, что часть закомментирована на время. Для большей части приложения используется источник данных не-XA, где я вижу тупики.
Может кто-нибудь сказать, пожалуйста, как мне решить проблему тупика? Я хочу понять, что пошло не так в дизайне. Любая помощь с благодарностью
2 ответа
Решение
Наконец, я справился без пробега, сделав следующее:
- hibernate.connection.isolation = 2
- Добавлено "для обновления с помощью cs" в конце моих операторов выбора.
- Я использовал метод спящего режима saveOrUpdate() для обновления и вставки. Теперь вместо этого я использую save() для вставки и update() для обновления.
Одна вещь, которую я не понял, заключалась в том, что использование "with ur" в конце моих операторов select не помогло устранить взаимоблокировки по сравнению с "with cs", который я сейчас использую. У Wonder есть уровень изоляции базы данных, который 'rs' должен с этим что-то делать?
Поскольку вы выполняете несколько вставок, обновлений, удалений, я хотел бы предложить вам добавить
<property name="hibernate.connection.autocommit" value="false"/>
И как только все ваши запросы будут выполнены успешно, сделайте коммит вручную connection.commit();
Может быть, это может помочь вам.