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

Asa*_*ika 23 java spring deadlock annotations transactions

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

谢谢,

阿萨夫

aar*_*ron 15

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

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

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

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


and*_*oso 8

我建议使用类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"/>
Run Code Online (Sandbox Code Playgroud)

但是,如果您仍然希望自己实现它,那么Spring文档中的AOP示例是一个良好的开端.

  • 谢谢你提到spring-retry项目. (2认同)

den*_*nov 4

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

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