Java中RollbackException的处理
有什么办法可以“重放”交易吗? 我的意思是,有时我会收到 RollbackException 并回滚事务。然后我可以“克隆”事务并重试,或者一旦调用回滚,事务就会丢失吗? 我真的需要这些更改,并且真的不想跟踪每个更改以便稍后重新运行...
谢谢, 乌迪
Is there any way to "replay" transaction?
I mean, sometimes I get RollbackException and rollback the transaction. Can I then "clone" the transaction and try again, or once rollback is called, transaction is lost?
I really need the changes, and really don't want to trace every change for rerunning later...
thanks,
udi
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
为什么你首先会遇到异常?在我看来,这就是问题的关键。
你依赖乐观的写作吗?如果是这样,那么您将必须以某种形式的循环包装数据库写入,并结合(可能)回退和多次重试。不幸的是,您无法自动执行此操作(除非您研究某种形式的包装数据库的 AOP 解决方案使用重试策略写入?)
Why do you get the exception in the first place ? This seems to me to be the crux of the matter.
Are you relying on optimistic writing ? If so, then you'll have to wrap your database writes in some form of loop, incorporating (perhaps) a backoff and a number of retries. You can't do this automatically, unfortunately (unless you investigate some form of AOP solution wrapping your database writes with a retry strategy ?)
这取决于交易来自哪里。在 Java/JDBC 中,事务与连接相关联。您可以通过将
setAutoCommit()
设置为 false 来启动一个事务(否则,每个语句都会变成自己的小事务)。没有什么可以阻止您在事务失败后重用连接(即您调用回滚)。
当您使用 Spring 时,事情会变得更加棘手。 Spring 将您的方法包装在事务处理程序中,并且该处理程序尝试根据方法中抛出的异常来猜测它应该对当前事务执行什么操作。下一个问题是:哪个包装器创建了当前事务?我刚刚遇到一个情况,我会调用一个方法
foo()
,该方法又会调用bar()
,两者都是@Transactional
。我想捕获
foo()
中bar()
的错误并将它们保存到数据库中。这不起作用,因为事务是为foo()
创建的(所以我仍然处于 Spring 认为被bar()
中的异常破坏的事务中)并且它不让我保存错误。解决方案是创建
baz()
,使其成为@Transactional(propagation=Propagation.REQUIRES_NEW)
并从foo()
调用它。baz()
将获得一个新的、全新的事务,并且能够写入数据库,即使它是从已经有一个(损坏的)事务的foo()
调用的。That depends where that transaction comes from. In Java/JDBC, a transaction is tied to a connection. You start one by setting
setAutoCommit()
to false (otherwise, every statement becomes its own little transaction).There is nothing preventing you from reusing the connection after a transaction failed (i.e. you called rollback).
Things get more tricky when you use Spring. Spring wraps your methods in a transaction handler and this handler tries to guess what it should do with the current transaction from the exceptions that get thrown in the method. The next question is: Which wrapper created the current transaction? I just had a case where I would call a method
foo()
which would in turn callbar()
, both@Transactional
.I wanted to catch errors from
bar()
infoo()
and save them into the DB. That didn't work because the transaction was created forfoo()
(so I was still in a transaction which Spring thought broken by the exception inbar()
) and it wouldn't let me save the error.The solution was to create
baz()
, make it@Transactional(propagation=Propagation.REQUIRES_NEW)
and call it fromfoo()
.baz()
would get a new, fresh transaction and would be able to write to the DB even though it was called fromfoo()
which already had a (broken) transaction.另一种选择是使用 JDBC 保存点 部分滚动后退。
Another alternative is to use JDBC savepoints to partly roll back.