【发布时间】:2018-07-15 21:59:21
【问题描述】:
环境: WildFly10.1, EJB3.1、JPA、甲骨文
这个问题看起来与之前提出的问题相似,但我无法得到答案。
我有一个处理付款的多线程批处理应用程序:一个 EJB 方法(由 Timer Bean 触发)从数据库中检索未处理的付款,将付款分成块,然后将这些块发送到另一个 EJB 方法(异步)进行处理.示例代码如下:
@Stateless
@LocalBean
public class PaymentProcessor {
@EJB
private PaymentFacade paymentFacade;
@EJB
private PaymentExecuter paymentExecuter;
public void processNegativeTrackerBatch() {
List<Payment> paymentList = paymentFacade.findPendingPaymentEntries();
// Each PaymentBlock represent a thread
List<PaymentBlock> paymentBlockList = splitPaymentsIntoBlocks(paymentList, NUMBER_OF_THREADS);
for (PaymentBlock block : paymentBlockList) {
paymentExecuter.processPayment(block.paymentList());
}
}
}
@Stateless
@LocalBean
public class PaymentExecuter {
@EJB
private PaymentFacade paymentFacade;
@Asynchronous
public Future<PaymentResults> processPayment(List<Payment> paymentList) {
PaymentResults paymentResults = new PaymentResults("SUCCESS");
for (Payment payment : paymentList) {
try {
//update acount balances (code removed)
//The following code cause oracle to threw ORA-00060: deadlock detected while waiting for resource
payment.setLoaded((short) 1);
payment.setDateLoaded(new Date());
paymentFacade.edit(payment);
} catch (Exception ex) {
paymentResults.setResponseCode("PARTIAL FAIL");
//log exception
}
}
return new AsyncResult<PaymentResults>(paymentResults);
}
}
上述代码在生产环境中wildfly中JTA设置为true时抛出如下异常:
javax.ejb.EJBTransactionRolledbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.3.v20160218-180e602): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: ORA-00060: deadlock detected while waiting for resource
Error Code: 60
Call: UPDATE PAYMENT SET DATE_LOADED = ?, LOADED = ? WHERE (ID = ?)
bind => [2018-07-05 01:07:22.225, 1, 650133]
Query: UpdateObjectQuery(za.co.company.persistence.entities.Payment[ id=650133 ])
at org.jboss.as.ejb3.tx.CMTTxInterceptor.handleInCallerTx(CMTTxInterceptor.java:159)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInCallerTx(CMTTxInterceptor.java:256)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.required(CMTTxInterceptor.java:329)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:239)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
at org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
at org.jboss.as.ejb3.component.invocationmetrics.WaitTimeInterceptor.processInvocation(WaitTimeInterceptor.java:47)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
at org.jboss.as.ejb3.security.SecurityContextInterceptor.processInvocation(SecurityContextInterceptor.java:100)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
at org.jboss.as.ejb3.deployment.processors.StartupAwaitInterceptor.processInvocation(StartupAwaitInterceptor.java:22)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
at org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
at org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:67)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
at org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
at org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:54)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:340)
at org.jboss.invocation.ContextClassLoaderInterce
...但是,即使使用完全相同的数据,我也无法在预生产环境中成功复制上述事件。
我的问题:
如果付款是唯一的,并且我确定没有付款记录在多个线程中结束,为什么会发生死锁?
如何复制死锁
我怎样才能发现真正发生的事情以便修复它?
请帮忙。感谢您提供任何帮助或推荐材料。
以下是有关 oracle 跟踪的一些信息:
2018-07-05 01:02:39.569*:ksq.c@12954:ksqdld_hdr_dump(): 检测到死锁 (ORA-00060) 请参阅 My Oracle Support 中的注释 60.1 以解决 ORA-60 错误
[交易死锁]
以下死锁不是 ORACLE 错误。它是一个 由于用户在应用程序设计中的错误而导致的死锁 或发出不正确的临时 SQL。以下 信息可能有助于确定死锁:
死锁图: ------------拦截者------------ ------------服务员------- ----- 资源名称 进程会话保持等待串行 进程会话保持等待串行 TX-00290020-0016FF24-00000000-00000000 161 463 X 908 173 467 S 29672 TX-0027000C-001C7991-00000000-00000000 173 467 X 29672 161 463 S 908
*** 2018-07-05T01:02:39.575960+02:00 dbkedDefDump():启动非事件诊断转储(标志=0x0,级别=1,掩码=0x0) ----- 错误堆栈转储 ----- ----- 此会话的当前 SQL 语句 (sql_id=6aju12kbrg657) ----- UPDATE PAYMENT SET LOADED = :1 , DATE_LOADED = :2 WHERE (ID = :3)
【问题讨论】:
-
当出现死锁错误时,会生成一个死锁跟踪文件,该文件将为您提供有关哪些进程发生冲突、它们持有哪些锁以及它们试图获取哪些锁的信息。该跟踪文件应该为您提供很多有用的信息。
-
感谢您的回复@JustinCave。我确实有一个跟踪文件。我找不到比我在 java 错误日志中看到的更好的信息,但是当我开始核心数据库管理工作时,我并没有那么清楚。我怎样才能学会更好地阅读这个文件?
-
网上有几篇关于阅读死锁痕迹的文章(这里有一个SO问题,例如stackoverflow.com/questions/17358088/…)。但是,如果您将死锁跟踪的相关部分编辑到您的问题中,您可能会获得更多帮助。
-
谢谢贾斯汀。我会看看这个。
标签: oracle jpa wildfly java-ee-6 ejb-3.1