java 如何在 Spring 中在死锁/锁定超时时重新启动事务?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1762870/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 17:52:08  来源:igfitidea点击:

How to restart transactions on deadlock/lock-timeout in Spring?

javaspringtransactionsannotationsdeadlock

提问by Asaf Mesika

What is the best practice on implementing a transaction restart upon deadlock or lock timeout exceptions when using Spring (specifically the Spring recommended approach: declarative transactions) ?

在使用 Spring(特别是 Spring 推荐的方法:声明性事务)时,在死锁或锁定超时异常时实现事务重启的最佳实践是什么?

Thanks,

谢谢,

Asaf

阿萨夫

回答by aaron

I feel like Spring itself should have a good answer to this question (in the form of documentation, at the least, or a retry interceptor of some sort). Alas, it does not.

我觉得 Spring 本身应该对这个问题有一个很好的答案(至少以文档的形式,或者某种重试拦截器)。唉,它没有。

Probably the best way to handle retries (if you want to continue being "declarative" about things) is to write your own interceptor implementation that will automatically retry the transaction a configured number of times. For starters, study Spring's TransactionInterceptor, which manages begin/rollback/commit behavior for declarative transactions. If you're using Hibernate, note how it handles Hibernate session binding/unbinding to the current Thread.

可能处理重试的最佳方法(如果您想继续对事物保持“声明性”)是编写您自己的拦截器实现,该实现将自动重试事务配置的次数。首先,研究 Spring 的TransactionInterceptor,它管理声明性事务的开始/回滚/提交行为。如果您正在使用 Hibernate,请注意它如何处理 Hibernate 会话绑定/解除绑定到当前线程。

Things to watch out for if you're using Hibernate:

使用 Hibernate 时需要注意的事项:

  • Your "retry interceptor" should be sure to unbind any preexisting thread-bound Hibernate session and rebind a new one. Once an exception (e.g., deadlock) is thrown from within Hibernate/JDBC code the corresponding Hibernate session is poisoned and needs to be discarded. (session.clear()is not sufficient.)
  • Be careful if your transactional service methods use Hibernate session objects as method parameters. On retry, when you reset your Hibernate session, these objects will be detached. You'll need to reattach them if the service method assumes they are attached (e.g., if they use lazy loaded properties that get accessed in the service method, or if you try to save them, etc.) In general, it's better if you don't use Hibernate objects as parameters to transactional service methods.
  • You'll be implementing MethodInterceptor.invoke()-- the MethodInvocationinstance that gets passed in to this may be stateful; you may need to clone it before using it in the interceptor.
  • 您的“重试拦截器”应该确保取消绑定任何先前存在的线程绑定 Hibernate 会话并重新绑定一个新会话。一旦从 Hibernate/JDBC 代码中抛出异常(例如,死锁),相应的 Hibernate 会话就会中毒并需要丢弃。(session.clear()是不够的。)
  • 如果您的事务服务方法使用 Hibernate 会话对象作为方法参数,请小心。重试时,当您重置 Hibernate 会话时,这些对象将被分离。如果服务方法假定它们是附加的(例如,如果它们使用在服务方法中访问的延迟加载的属性,或者如果您尝试保存它们等),您将需要重新附加它们。不要使用 Hibernate 对象作为事务服务方法的参数。
  • 您将实现MethodInterceptor.invoke()——MethodInvocation传递给 this的实例可能是有状态的;在拦截器中使用它之前,您可能需要克隆它。

回答by andrecardoso

I recommend using the class org.springframework.retry.interceptor.RetryOperationsInterceptorfrom the spring retry project, configured like this:

我建议使用类org.springframework.retry.interceptor.RetryOperationsInterceptor从春天重试项目,配置就像这样

<aop:config>
    <aop:pointcut id="transactional" expression="execution(* com...*Service.remoteCall(..))" />
    <aop:advisor pointcut-ref="transactional" advice-ref="retryAdvice" order="-1"/>
</aop:config>

<bean id="retryAdvice" class="org.springframework.retry.interceptor.RetryOperationsInterceptor"/>

But if you still want to implement it by yourself, the example of AOP from spring documentationis a good start.

但是如果你还想自己实现,spring文档中的AOP示例是一个很好的开始。

回答by Archie

I had the same question several years ago and ended up writing my own solutionas an AOP aspect, which ends up looking like this in your code:

几年前我遇到了同样的问题,最终将我自己的解决方案编写为 AOP 方面,最终在您的代码中看起来像这样:

  @RetryTransaction
  @Transactional
  public void doSomething() {
      ....
  }

回答by denis.zhdanov

There is no universal answer because it depends on application specifics. For example you may want to perform automatic transacted operation restart or notify the user about operation failure and ask for explicit retry confirmation etc.

没有通用的答案,因为这取决于应用程序的具体情况。例如,您可能希望执行自动事务操作重新启动或通知用户操作失败并要求显式重试确认等。

I'd use AOP in case of automatic restart scenario.

我会在自动重启的情况下使用 AOP。