我们将Spring,Hibernate和MySQL用于我们的应用程序。但有时查询会生成 CannotAcquireLockException ,代码如下所示。
public Ledger[] storeOrUpdateLedgers(Ledger[] ledgers,int iClinicId) throws DataAccessException {
List<Ledger> ledgerList = new ArrayList<Ledger>();
for(int i = 0; i < ledgers.length; i++) {
ledgers[i].setiClinicId(iClinicId);
ledgerList.add(ledgers[i]);
}
for(int i = 0; i < ledgerList.size(); i++) {
getHibernateTemplate().clear();
getHibernateTemplate().saveOrUpdate(ledgerList.get(i));
getHibernateTemplate().flush();
}
}
public class Ledger implements Serializable {
private int iLedgerId;
private int iClinicId;
private int iPatientId;
private int iProviderId;
private int iVisitId;
private int iPaymentId;
private int iClaimId;
private int iProcedureId;
private String sDate;
private double dAmount;
private byte btType;
private String sDesc;
private byte btCurrParty;
private int iCurrPartyId;
private byte btRespParty;
private int iRespPartyId;
private boolean active;
private int iParentId;
private int iReasonId;
private String sDos;
private int iU_ID;
private String sEntryDate; // no mapping required
public int getiU_ID() {
return iU_ID;
}
public void setiU_ID(int iUID) {
iU_ID = iUID;
}
public int getiLedgerId() {
return iLedgerId;
}
public void setiLedgerId(int iLedgerId) {
this.iLedgerId = iLedgerId;
}
public int getiClinicId() {
return iClinicId;
}
public void setiClinicId(int iClinicId) {
this.iClinicId = iClinicId;
}
public int getiPatientId() {
return iPatientId;
}
public void setiPatientId(int iPatientId) {
this.iPatientId = iPatientId;
}
public int getiProviderId() {
return iProviderId;
}
public void setiProviderId(int iProviderId) {
this.iProviderId = iProviderId;
}
public int getiVisitId() {
return iVisitId;
}
public void setiVisitId(int iVisitId) {
this.iVisitId = iVisitId;
}
public int getiPaymentId() {
return iPaymentId;
}
public void setiPaymentId(int iPaymentId) {
this.iPaymentId = iPaymentId;
}
public int getiClaimId() {
return iClaimId;
}
public void setiClaimId(int iClaimId) {
this.iClaimId = iClaimId;
}
public int getiProcedureId() {
return iProcedureId;
}
public void setiProcedureId(int iProcedureId) {
this.iProcedureId = iProcedureId;
}
public String getsDate() {
return sDate;
}
public void setsDate(String sDate) {
this.sDate = sDate;
}
public double getdAmount() {
return dAmount;
}
public void setdAmount(double dAmount) {
this.dAmount = dAmount;
}
public byte getbtType() {
return btType;
}
public void setbtType(byte btType) {
this.btType = btType;
}
public String getsDesc() {
return sDesc;
}
public void setsDesc(String sDesc) {
this.sDesc = sDesc;
}
public byte getbtCurrParty() {
return btCurrParty;
}
public void setbtCurrParty(byte btCurrParty) {
this.btCurrParty = btCurrParty;
}
public int getiCurrPartyId() {
return iCurrPartyId;
}
public void setiCurrPartyId(int iCurrPartyId) {
this.iCurrPartyId = iCurrPartyId;
}
public byte getbtRespParty() {
return btRespParty;
}
public void setbtRespParty(byte btRespParty) {
this.btRespParty = btRespParty;
}
public int getiRespPartyId() {
return iRespPartyId;
}
public void setiRespPartyId(int iRespPartyId) {
this.iRespPartyId = iRespPartyId;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
public int getiParentId() {
return iParentId;
}
public void setiParentId(int iParentId) {
this.iParentId = iParentId;
}
public int getiReasonId() {
return iReasonId;
}
public void setiReasonId(int iReasonId) {
this.iReasonId = iReasonId;
}
public String getsDos() {
return sDos;
}
public void setsDos(String sDos) {
this.sDos = sDos;
}
public String getsEntryDate() {
return sEntryDate;
}
public void setsEntryDate(String sEntryDate) {
this.sEntryDate = sEntryDate;
}
}
Hibernate映射:
<class name="com.iris.allofactor.data.vo.Ledger" table="LEDGER">
<id name="iLedgerId" column="LEDGER_ID" unsaved-value="0">
<generator class="native"/>
</id>
<property name="iClinicId" column="CLINIC_ID"></property>
<property name="iPatientId" column="PATIENT_ID"></property>
<property name="iProviderId" column="PROVIDER_ID"></property>
<property name="iVisitId" column="VISIT_ID"></property>
<property name="iPaymentId" column="PAYMENT_ID"></property>
<property name="iClaimId" column="CLAIM_ID"></property>
<property name="iProcedureId" column="PROCEDURE_ID"></property>
<property name="sDate" column="DATE"></property>
<property name="dAmount" column="AMOUNT"></property>
<property name="btType" column="TYPE"></property>
<property name="sDesc" column="DESCRIPTION"></property>
<property name="btCurrParty" column="CURR_PARTY"></property>
<property name="iCurrPartyId" column="CURR_PARTY_ID"></property>
<property name="btRespParty" column="RESP_PARTY"></property>
<property name="iRespPartyId" column="RESP_PARTY_ID"></property>
<property name="active" column="ACTIVE"></property>
<property name="iParentId" column="PARENT_ID"></property>
<property name="iReasonId" column="REASON_ID"></property>
<property name="sDos" column="DOS"></property>
<property name="iU_ID" column="USER_ID"></property>
</class>
Stacktrace如下:
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:244)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
at org.springframework.orm.hibernate3.HibernateAccessor.convertJdbcAccessException(HibernateAccessor.java:424)
at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:410)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:424)
at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
at org.springframework.orm.hibernate3.HibernateTemplate.flush(HibernateTemplate.java:890)
at com.iris.allofactor.data.dao.hibernate.HibernateLedgerDao.storeOrUpdateLedgers(HibernateLedgerDao.java:97)
at com.iris.allofactor.data.dao.impl.LedgerAuditBODaoImpl.storeOrUpdateLedgers(LedgerAuditBODaoImpl.java:64)
at com.iris.allofactor.data.dao.impl.ChargesDaoImpl.storeOrUpdateCharges(ChargesDaoImpl.java:844)
at com.iris.allofactor.data.dao.impl.ClaimEncounterBODaoImpl.addorEditClaimWhileClaimIdAndVisitIdIsPresent(ClaimEncounterBODaoImpl.java:1072)
at com.iris.allofactor.data.dao.impl.ClaimEncounterBODaoImpl.storeOrUpdateClaim(ClaimEncounterBODaoImpl.java:819)
at com.iris.allofactor.data.dao.facade.DaoFacadeImpl.storeOrUpdateClaim(DaoFacadeImpl.java:1915)
at sun.reflect.GeneratedMethodAccessor2549.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy2.storeOrUpdateClaim(Unknown Source)
at com.iris.allofactor.services.impl.ClaimServiceImpl.addorEditClaim(ClaimServiceImpl.java:447)
at com.iris.allofactor.services.soap.impl.ClaimWebServiceImpl.addorEditClaim(ClaimWebServiceImpl.java:337)
at sun.reflect.GeneratedMethodAccessor2548.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.axis.providers.java.RPCProvider.invokeMethod(RPCProvider.java:397)
at org.apache.axis.providers.java.RPCProvider.processMessage(RPCProvider.java:186)
at org.apache.axis.providers.java.JavaProvider.invoke(JavaProvider.java:323)
at org.apache.axis.strategies.InvocationStrategy.visit(InvocationStrategy.java:32)
at org.apache.axis.SimpleChain.doVisiting(SimpleChain.java:118)
at org.apache.axis.SimpleChain.invoke(SimpleChain.java:83)
at org.apache.axis.handlers.soap.SOAPService.invoke(SOAPService.java:453)
at org.apache.axis.server.AxisServer.invoke(AxisServer.java:281)
at org.apache.axis.transport.http.AxisServlet.doPost(AxisServlet.java:699)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at org.apache.axis.transport.http.AxisServletBase.service(AxisServletBase.java:327)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:619)
它反复生成此异常,我认为我的方法存在一些问题。
答案 0 :(得分:12)
这是明确的死锁情况。这与MySQL错误相关,而不是与类的Hibernate问题相关。首先让我们回顾一下死锁的定义:
死锁是两种或更多竞争行为的情况 每个人都在等待对方完成,因而也没有。
有关详细信息,请参阅此页面:http://en.wikipedia.org/wiki/Deadlock
你如何处理这种情况。那么,您需要阅读以下文章:Deadlocks in InnoDB。它包含您需要的大部分信息。本文详细解释了如何跟踪和处理它必须阅读的死锁。
基本上,您需要根据以上信息执行以下步骤:
关于InnoDB的文章也有一系列补救措施,所以我不打算在此重申。请记住死锁不是致命错误,您只需要处理它。所以可能会捕获异常并重试事务。还要确保Hibernate生成的查询是最佳的,因为他们正在使用索引等等。您可以尝试的另一件事是批处理 Hibernate上的事务在批处理中执行。
我确信通过上面的两个链接,您将能够处理问题,并且您自己完成这项工作将是宝贵的经验。如果你发现任何特定的项目你有问题,请将其添加到问题中,让我们处理。
答案 1 :(得分:9)
我想知道您的问题是否与此主题中讨论的问题类似:Deadlock problems with Hibernate/Spring/MS-SQL。此特定问题的根本原因是您有一个线程对数据库执行查找/选择,而另一个线程正在尝试对数据库执行删除/插入。该线程中有2个解决方案。
第一个优化了查找和删除代码,使其成为一个SQL
命令而不是两个。
# sql sudo code
# original query
find me this row where this=that
delete this row
# better query
delete this row where this=that
第二个建议的解决方案是在COLUMNS
子句中使用WHERE
创建索引,以便数据库不再锁定ROW
,但现在会锁定密钥索引。
答案 2 :(得分:0)
MySQL 列表中可能存在未完成的会话。它可能仍在运行。因为您的应用程序中的程序员或使用数据库的程序员的错误。
例如,您启动了一个会话,但由于错误,该进程卡住了,没有回滚。 **这种情况很少发生。
请手动删除所有会话
获取所有会话
SHOW FULL PROCESSLIST;
然后通过id杀死他们
KILL 192;
示例。
mysql> SHOW PROCESSLIST;
+-----+------+-----------------+------+---------+------+-------+---------------+
| Id | User | Host | db | Command | Time | State | Info |
+-----+------+-----------------+------+---------+------+-------+----------------+
| 143 | root | localhost:61179 | cds | Query | 0 | init | SHOW PROCESSLIST |
| 192 | root | localhost:53793 | cds | Sleep | 4 | | NULL |
+-----+------+-----------------+------+---------+------+-------+----------------+
2 rows in set (0.00 sec)
mysql> KILL 192;
Query OK, 0 rows affected (0.00 sec)