2011-06-14 35 views
2

有時,由於嘗試訪問MySQL時發生簡單的SocketException,所以db事務無法啓動。在當前代碼庫中,所有SQL或JPQL代碼都駐留在具有@Transactional註釋(org.springframework.transaction.annotation)的類中。爲每個方法調用一個帶註釋的類創建一個事務。這使得編寫可以在所有db調用中重用的代碼變得很困難。強制Spring/JPA/Hibernate/JDBC重試失敗的beginTransaction?

一個解決方案是將數據庫代碼放入循環中:它會重試幾次事務。這工作,但我不想灑我的代碼充滿循環(每個數據庫調用一個)。

是他們的一種方法,使以下任一框架的一個重試失敗的BeginTransaction自動?:春天,JPA,休眠,C3P0,MySQL JDBC驅動程序

僅供參考,這裏是一片日誌:

java.net.SocketException 
MESSAGE: Connection reset 

STACKTRACE: 
java.net.SocketException: Connection reset 
     at java.net.SocketInputStream.read(SocketInputStream.java:168) 
     at com.mysql.jdbc.util.ReadAheadInputStream.fill(ReadAheadInputStream.java:113) 
     at com.mysql.jdbc.util.ReadAheadInputStream.readFromUnderlyingStreamIfNecessary(ReadAheadInputStream.java:160) 
     at com.mysql.jdbc.util.ReadAheadInputStream.read(ReadAheadInputStream.java:188) 
     at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:1910) 
     at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2304) 
     at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2803) 
     at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1573) 
     at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1665) 
     at com.mysql.jdbc.Connection.execSQL(Connection.java:3170) 
     at com.mysql.jdbc.Connection.setAutoCommit(Connection.java:5273) 
     at com.mchange.v2.c3p0.impl.NewProxyConnection.setAutoCommit(NewProxyConnection.java:881) 
     at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:91) 
     at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1353) 
     at org.hibernate.ejb.TransactionImpl.begin(TransactionImpl.java:38) 
     at org.springframework.orm.jpa.DefaultJpaDialect.beginTransaction(DefaultJpaDialect.java:70) 
     at org.springframework.orm.jpa.vendor.HibernateJpaDialect.beginTransaction(HibernateJpaDialect.java:52) 
     at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:330) 
     at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:374) 
     at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:263) 
     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:101) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171) 
     at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) 

PS。我討厭可以解決所有問題的automagic框架。這不是我做這個項目的決定。

+2

你說的代碼已經創造了太多的交易,並重新嘗試將創造更多。似乎是時候修復應用程序如何執行交易。 – 2011-06-14 15:14:42

+0

我不知道你在使用什麼數據源,但是你可以通過配置來解決這個問題。例如,apache commons BasicDataSource有testOnBorrow,validationQuery和removeAbandoned,以幫助確保您獲得有效的連接。 http://commons.apache.org/dbcp/apidocs/org/apache/commons/dbcp/BasicDataSource.html – 2011-06-14 15:27:12

+0

如果我有機會重做事務處理,我將完全放棄Spring並直接轉到JPA(甚至更好:JDBC)。 – 2011-06-15 07:49:53

回答

2

如果您不想將重試循環帶入代碼,也許可以使用AOP來實現重試功能。在Spring文檔中有這樣一個建議的example

+0

然後我不得不使用手動事務處理? – 2011-06-15 07:45:30

+0

不,您可以指定在現有交易建議之前或之後發生的建議的「訂單」(取決於您是要在現有交易中重試還是在每次重試時開始新建交易)。 – opyate 2013-02-09 08:24:32

0

創建一個將TransactionCallback作爲參數的實用方法。在該方法中,使用TransactionTemplate進行循環和異常處理。

當您需要使用重試運行查詢時,請使用此方法。

有關詳細信息,請參閱Spring Reference

例如,調用代碼看起來像:

public Object someServiceMethod() { 
    return yourUtilityObj.retry(new TransactionCallback() { 

    public Object doInTransaction(TransactionStatus status) { 
     updateOperation1(); 
     return resultOfUpdateOperation2(); 
    } 
    }); 
} 
+0

你建議我使用手動事務處理。也許這是要走的路。我希望有一個簡單的重試=真正的國旗... – 2011-06-15 07:47:20

+0

這將是一個偉大的增強@Transaction!投票在https://jira.springsource.org/browse/SPR-5890 – sourcedelica 2011-06-16 06:00:59

+0

查看http://java.dzone.com/articles/automatic-deadlock-retry – sourcedelica 2011-07-07 12:51:39