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

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

谢谢,

阿萨夫

我觉得Spring本身应该对这个问题有一个很好的答案(至少是文档forms,或者是某种重试拦截器)。 唉,事实并非如此。

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

如果你正在使用Hibernate,需要注意的事项:

  • 你的“重试拦截器”应该确保取消绑定任何预先存在的线程绑定的Hibernate会话并重新绑定一个新的。 一旦从Hibernate / JDBC代码中抛出exception(例如,死锁),相应的Hibernate会话就会中毒并且需要被丢弃。 ( session.clear()是不够的。)
  • 如果您的事务服务方法使用Hibernate会话对象作为方法参数,请务必小心。 重试时,重置Hibernate会话时,这些对象将被分离。 如果服务方法假定它们被附加(例如,如果它们使用在服务方法中访问的延迟加载属性,或者如果您尝试保存它们等等),则需要重新附加它们。一般情况下,如果您更好不要将Hibernate对象用作事务服务方法的参数。
  • 您将实现MethodInterceptor.invoke() – 传入此方法的MethodInvocation实例可能是有状态的; 您可能需要在拦截器中使用它之前克隆它。

我建议使用spring retry 项目中的类org.springframework.retry.interceptor.RetryOperationsInterceptor ,配置如下:

      

但是如果你仍然想自己实现它,那么Spring文档中的AOP示例是一个好的开始。

没有通用答案,因为它取决于应用程序细节。 例如,您可能希望执行自动事务处理操作重启或通知用户操作失败并要求显式重试确认等。

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

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

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