强制 Spring/JPA/Hibernate/JDBC 重试失败的 beginTransaction?

发布于 2024-11-15 03:46:43 字数 2690 浏览 3 评论 0 原文

有时,在尝试访问 MySQL 时,数据库事务会因为简单的 SocketException 而无法开始。在当前的代码库中,所有 SQL 或 JPQL 代码都驻留在带有 @Transactional 注释(org.springframework.transaction.annotation)的类中。为我创建一个事务,用于对带注释的类的每个方法调用。这使得编写可在所有数据库调用中重用的代码变得困难。

一种解决方案是将数据库代码放在循环中:它将重试事务几次。这是可行的,但我不想让我的代码充满循环(每个数据库调用一个)。

他们是让以下框架之一自动重试失败的 beginTransaction 的方法吗?:Spring、JPA、Hibernate、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。我讨厌据说可以解决所有问题的自动框架。在这个项目中这不是我做出的决定。

Sometimes a db transaction can't begin because of a simple SocketException when trying to reach MySQL. In the current codebase, all SQL or JPQL code resides in classes with the @Transactional annotation (org.springframework.transaction.annotation). A transaction is created for me for each method call to an annotated class. This makes it difficult to write code that can be reused across all db calls.

One solution would be to put the db code within a loop: It will retry the transaction a few times. This works but I'd prefer not to sprinkle my code full of loops (one for each db call).

Is their a way to make either one of the following frameworks retry a failed beginTransaction automatically?: Spring, JPA, Hibernate, c3p0, MySQL JDBC driver

For reference, here is a piece of the log:

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. I hate automagic frameworks that supposedly solve all problems. It wasn't my decision to make in this project.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

超可爱的懒熊 2024-11-22 03:46:43

如果您不想在代码中引入重试循环,也许您可​​以使用 AOP 来实现重试功能。有一个 Spring 文档中此类建议的示例

If you don't want to bring retry loops into your code, perhaps you can use AOP to implement retry functionality. There is an example of such an advice in Spring documentation.

跨年 2024-11-22 03:46:43

创建一个实用程序方法,该方法采用 TransactionCallback 作为参数。在该方法中,使用 交易模板

当您需要重试运行查询时,请使用此方法。

请参阅 Spring 参考细节。

例如,您的调用代码如下所示:

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

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

Create a utility method that takes a TransactionCallback as a parameter. In that method do the looping and exception handling, using a TransactionTemplate.

When you need to run a query with retries use this method.

See the Spring Reference for details.

For example, your calling code would look like:

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

    public Object doInTransaction(TransactionStatus status) {
      updateOperation1();
      return resultOfUpdateOperation2();
    }
  });
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文