如何在 Spring 中重新启动死锁/锁定超时事务?
在使用 Spring 时,在死锁或锁定超时异常时实现事务重启的最佳实践是什么(特别是 Spring 推荐的方法:声明性事务)?
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 本身应该对这个问题有一个很好的答案(至少以文档的形式,或者某种重试拦截器).唉,它没有.
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 的 TransactionInterceptor
,它管理声明式事务的开始/回滚/提交行为.如果您使用的是 Hibernate,请注意它如何处理 Hibernate 会话绑定/取消绑定到当前线程.
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.
使用 Hibernate 时需要注意的事项:
Things to watch out for if you're using Hibernate:
- 您的重试拦截器"应确保取消绑定任何预先存在的线程绑定 Hibernate 会话并重新绑定一个新会话.一旦从 Hibernate/JDBC 代码中抛出异常(例如,死锁),相应的 Hibernate 会话就会中毒,需要丢弃.(
session.clear()
是不够的.) - 如果您的事务服务方法使用 Hibernate 会话对象作为方法参数,请小心.重试时,当您重置 Hibernate 会话时,这些对象将被分离.如果服务方法假定它们已附加,则需要重新附加它们(例如,如果它们使用在服务方法中访问的延迟加载属性,或者如果您尝试保存它们等).一般来说,最好是不要使用 Hibernate 对象作为事务服务方法的参数.
- 您将实现
MethodInterceptor.invoke()
-- 传入 this 的MethodInvocation
实例可能是有状态的;在拦截器中使用它之前,您可能需要克隆它.
- 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()
-- theMethodInvocation
instance that gets passed in to this may be stateful; you may need to clone it before using it in the interceptor.
相关文章