如何在Spring事务管理中调用自定义的回滚方法?
环境:Spring 3、自定义事务管理、JDBC 事务
我刚刚阅读了有关使用事务模板来处理事务管理的 Spring 文档。 这似乎过于复杂,所以我想问:
我的大多数事务都与 JDBC 相关,这意味着我只需在我的服务上声明一个 @Transactional
。但现在我正在对另一个站点进行 REST 服务调用,如果以下任何 JDBC 操作失败,该站点需要回滚,在这种情况下我将提供回滚代码。
随着我在方法中的进展,在我的事务中 - 我想保存对 REST 服务调用的引用(需要回滚该操作),并且在出现异常时我只是想要一个方法< code>myCustomRollback() 调用,它可以访问之前存储的对象。
为什么不在 transactionTemplate 中提供一个映射来存储内容并在 @Transactional 注释上定义自定义回滚方法?
这就是我的想法,我没有遵循 Spring 的想法。有人可以帮助我弥合我想要的东西和我如何在 Spring 中最有效地实现它之间的差距吗?我只需要对一些特殊情况操作执行此操作。
Environment: Spring 3, Custom Transaction Management, JDBC Transactions
I just read the Spring docs on using the transaction template to handle transaction management. It seemed overly complex so I want to ask:
Most of my transactions are JDBC related, meaning I just declare an @Transactional
on my service. But now I am making a REST service call to another site which needs to rollback if any of the following JDBC operations fail, I'll provide the rollback code in this case.
As I progress in my method, in my transaction - I want to save a reference to the REST service call (needed to roll back that action), and upon exception I just want a method myCustomRollback()
called which can access the previously stored object.
Why not just provide a map in the transactionTemplate for storing stuff and define a custom rollback method on the @Transactional
annotation?
This is the way I think about it, I'm not following the way Spring thinks about this. Can someone help me bridge the gap between what I want and how I accomplish it most efficiently in Spring? I only need to do this for a few special case operations.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
对于仍在阅读本文的任何人:
我解决了 Spring 事件的类似问题 - 正如选项 3 中 Den Roman 所建议的那样。
这是基本思想(场景是虚构的):
每当我执行需要与事务一起回滚的外部操作时,我都会使用 spring 的支持在我的
@Transactional
方法中发布一个事件(org.springframework.context.ApplicationEventPublisher
):事件本身可以是任何对象 - 我创建了一个 POJO,其中包含有关要删除的远程实体的详细信息。
然后我注册了一个特殊的事件监听器,它绑定到事务阶段 - 在我的例子中是回滚:
当然,建议 catch &记录回滚操作的异常,而不是丢失
placeOrder()
方法中的原始异常。默认情况下,这些事件是同步的,但可以通过其他配置将它们设为异步。
这是一篇关于该机制的非常好的文章,包括详细的配置和陷阱: 事务同步和 Spring应用程序事件 (DZone)
虽然我 100% 不喜欢这个解决方案,因为它用事件发布内容扰乱了业务逻辑并绑定到 spring,但它确实实现了我期望的功能,并且可以传递上下文从事务方法到回滚方法 - 这不能通过事务方法之外的传统 try/catch 块获得(除非您将上下文放在异常本身中,这不是很好)。
To anyone still reading this:
I solved a similar problem with spring events - as suggested by Den Roman in option 3.
Here's the basic idea (scenario is fictional):
Whenever I perform external operations that need to be rolled back together with the transaction, I publish an event inside my
@Transactional
method using support from spring (org.springframework.context.ApplicationEventPublisher
):The event itself can be any object - I created a POJO with details about the remote entity to be deleted.
Then I registered a special event listener that is bound to a transaction phase - in my case to the rollback:
Of course, it's recommended to catch & log the exception from rollback operation, not to lose the original exception from the
placeOrder()
method.By default these events are synchronous, but they can be made async by additional configuration.
Here's a very good article on this mechanism, including detailed configuration and pitfalls: Transaction Synchronization and Spring Application Events (DZone)
While I don't like the solution 100% because it clutters the business logic with event publishing stuff and binds to spring, it definitely does what I expect it to do and makes it possible to pass context from the transactional method to the rollback method - which is not available through a traditional try/catch block outside of the transactional method (unless you put your context in the exception itself, which is not very nice).
我已经重新阅读了你的问题几次,但不确定我是否完全理解你的问题。我假设您正在执行 someCode ,如果失败,您希望执行 myCustomRollback ,其中包含有关 someCode 的一些信息。所以我会尝试提供一个通用答案。
如果你想让spring回滚一些代码。它只会回滚 rollBackAble 的内容,就像 jdbc 事务一样。假设您有一个执行 2 次调用的方法。
所以上面的代码总是会回滚。它将撤消实体的持久化,但不会撤消文件的创建,因为它不是由 Spring 事务管理的,除非您为其提供自定义实现。
其次,Spring 提供了两种处理事务的方法:
aspectJ 方法似乎更难配置,但其实并没有那么难,而且更容易使用。因为用 @Transactional 注释的任何内容都将嵌入(编织)代码。对于 Spring AOP 来说,情况并非如此。例如 Spring 中的事务性内部方法调用将被忽略!所以aspectJ提供了一种更直观的方法。
回到我认为你的问题是什么(代码全部在 1 个类中):
上面的代码仅适用于 AspectJ! 因为你进行内部方法调用,这似乎也是私有的!运行时的 AOP 无法处理这个问题。
因此,执行中的所有内容(即 rollbackAble)都将被回滚。在 doStuff 中,您拥有有关执行中使用的对象的信息,您现在可以在 myCustomRollback 中使用来手动回滚 REST 内容。
不确定我是否正确回答了这个问题,但我希望它可以帮助有类似问题的人。
I've re-read your question a few times and am not sure I understand your question completely. I assume your executing someCode and if that fails you would like to execute myCustomRollback which has some information about someCode. So I'll try to provide a Generic answer.
If you want spring to rollback some code. It will only rollback that which is rollBackAble, like jdbc transactions. Assume you have a method which performs 2 calls.
So the code above will always rollback. It will undo the persisting of your entity, but not the creation of your file, since that is not managed by Spring transactions, unless you provide custom implementation for it to be.
Second, Spring provides 2 ways of working with transactions:
The aspectJ approach seems harder to configure, but isn't so much and is way easier to use. Since anything which is annotated with @Transactional will be embedded (weaved) with code. For Spring AOP this is not the case. Transactional inner method calls for instance in Spring will be ignored! So aspectJ provides a more intuitive approach.
Back to what I think your question is (the code is all in 1 class):
The code above will only work with AspectJ! Since your making inner method calls which also seems to be private! AOP at runtime cannot handle this.
So what happens is everything (which is rollbackAble) in execute will be rollbacked. And in doStuff you have information about the objects which were used in execute, you now can use in myCustomRollback to rollback your REST stuff manually.
Not sure if I answered this question properly, but I hope it helps someone with a similar problem.
1 解决方案是通过扩展一个来实现您自己的事务管理器
2 解决方案是使用 TransactionSynchronizationManager 类
3 解决方案是使用 @TransactionalEventListener 如果您有 Spring 4
1 solution is to implement your own transactional manager by extending a one
2 solution is to use TransactionSynchronizationManager class
3 solution is to use @TransactionalEventListener in case you have Spring 4
Spring事务管理自动回滚的默认行为是针对未检查的异常,
因此对于自定义异常,
如果存在与指定匹配的异常,则事务将回滚。如果异常不匹配,它会传播到服务的调用者或 TransactionRolledBackException 包装器(
如果您使用 org.springframework.transaction.PlatformTransactionManager),它比模板更易于管理处理异常,
请检查文档 http://static.springsource.org/spring/docs/3.0.x/spring -framework-reference/html/transaction.html
Spring transaction management the default behavior for automatic rollback is for unchecked exceptions
so for a custom exception,
the transaction be rolled back if it there is an exception that matches the specified. If an exception not matches, it is propagated to caller of the service or TransactionRolledBackException wrapper
if you use use the org.springframework.transaction.PlatformTransactionManager it is more manageable handling exceptions than template
check the documentation http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html
您可以使用 AfterThrowing 建议(当抛出异常时)&在那里调用您的方法 (
myCustmRollback()
),您可以使用TransactionSynchronizationManager
类来获取当前事务&将其回滚...或者..您可以使用 aroundAdvice 开始&提交/回滚您的事务(这样您可以通过使用
TransactionSynchronizationManager
类来使用 spring 提供的事务管理器)you can use the AfterThrowing advice (when an exception is thrown) & call your method (
myCustmRollback()
) there, you can useTransactionSynchronizationManager
class to get thecurrent transaction & roll it back...alternatively.. you can use the AroundAdvice to begin & commit/rollback your transaction (this way you can use the spring provided transaction manager by using the
TransactionSynchronizationManager
class)