如何在春季死锁/锁定超时时重新启动交易?

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

谢谢

阿萨夫


答案 1

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

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

如果您使用的是Hibernate,需要注意的事项:

  • 您的“重试拦截器”应确保解除绑定任何预先存在的线程绑定休眠会话,并重新绑定新会话。一旦从Hibernate/JDBC代码中抛出异常(例如,死锁),相应的Hibernate会话就会被毒害,需要被丢弃。(是不够的。session.clear()
  • 如果事务性服务方法使用休眠会话对象作为方法参数,请小心。重试时,重置休眠会话时,这些对象将被分离。如果服务方法假定它们已附加(例如,如果它们使用在服务方法中访问的延迟加载属性,或者如果您尝试保存它们,则需要重新附加它们。通常,最好不要使用 Hibernate 对象作为事务性服务方法的参数。
  • 您将实现 - 传入此的实例可能是有状态的;您可能需要先克隆它,然后再在拦截器中使用它。MethodInterceptor.invoke()MethodInvocation

答案 2

我建议使用 spring 重试项目中的类,其配置如下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"/>

但是,如果您仍然想自己实现它,那么来自spring文档的AOP示例是一个良好的开端。


推荐