使用 JDBC 3.0 实现对嵌套事务的支持

Posted

技术标签:

【中文标题】使用 JDBC 3.0 实现对嵌套事务的支持【英文标题】:Implementing support for nested transactions using JDBC 3.0 【发布时间】:2009-02-06 18:57:19 【问题描述】:

我们的旧版应用程序使用 JDBC 3.0。它通过实现自己的事务管理器来支持事务,该事务管理器能够为每个线程返回相同的 JDBC 连接。我最近发现的问题是它不支持嵌套事务:如果一个事务在另一个事务中启动,那么在内部事务的上下文中运行的每个 SQL 都将使用相同的数据库连接执行,并且当它被提交或回滚它将自动提交或回滚从外部事务开始的所有更改。

据我所知,我可以使用 JDBC 3.0 保存点实现对嵌套事务的支持:每当启动嵌套事务时,我都可以为当前连接设置一个新的保存点。之后,如果嵌套事务回滚,我将回滚到这个保存点。另一方面,如果它被承诺,我将什么也不做。只有最外层事务的提交才会将更改保存到数据库中。

这是正确的吗?这种方法有什么缺陷吗?如果是,我的可能性是什么?

谢谢。

【问题讨论】:

【参考方案1】:

代码中可能存在期望完成而不是延迟提交的依赖项(例如,如果隔离级别设置为 TRANSACTION_READ_COMMITTED)。

考虑修复您的事务管理器以在单独的连接上执行嵌套事务。

更新:看起来the Spring framework 使用 SavePoints 来提供嵌套事务。我的猜测是他们只是忽略了隔离模式的问题。

【讨论】:

我想过,但是万一外层事务回滚了怎么办?那么嵌套事务是否也会被回滚(在先前提交之后),即使它是在另一个连接上执行的? 不,嵌套事务不会回滚,因此它不再是真正的“嵌套”。 Spring 不会忽略隔离问题:ibm.com/developerworks/java/library/j-isolation duffymo,我在该参考资料中没有看到任何关于嵌套事务的内容。这是 JDBC 3 的问题——它的事务隔离定义不支持嵌套事务。【参考方案2】:

事务有点棘手,不能真正从 JDBC 层查看,而是从底层数据库本身查看。我将从这里开始谈论 Oracle,因为它是我最有经验的。在 Oracle 中,如果您启动事务,则可以回滚到事务中的保存点,但不能使用保存点提交。假设我启动了一个事务并拥有三个保存点 A、B 和 C。我可以愉快地前进和回滚到 A、B 或 C,但是一旦你提交,你就开始了一个新事务,现在是 A、B , 和 C 不再有效。我希望这能很好地回答你的问题。

【讨论】:

【参考方案3】:

您可以尝试Atomikos TransactionsEssentials 中的嵌套事务支持。

但是,DBMS 中的嵌套事务通常受到以下方式的限制:

-您的嵌套事务共享相同的数据库事务,这允许以回滚粒度为代价共享数据访问(您回滚整个事物)

-或者您的嵌套事务(由 Atomikos)映射到不同的底层数据库事务,代价是不允许对热点数据进行共享数据访问

这种不匹配是由于数据库事务的 ACID 特性造成的。最终,您所有的 DBMS 访问都必然发生在这样的数据库事务中。

如果您想自己完成一些事情,您提到的保存点方法听起来很有希望 - 但您可能需要确保对其进行广泛测试。

最好的 伙计

【讨论】:

以上是关于使用 JDBC 3.0 实现对嵌套事务的支持的主要内容,如果未能解决你的问题,请参考以下文章

java 启动jdbc 事务报错 嵌套异常

在 clojure.jdbc 和 postgres 中使用保存点进行测试的嵌套事务

无法提交 Hibernate 事务;嵌套异常是 org.hibernate.Transaction 异常:JDBC 提交失败

Laravel基于RT模式实现分布式事务(全球首创支持子服务嵌套事务)

网页显示无法打开JDBC连接事务;嵌套异常java.sql.SQLException:无法连接、 如何处理这种问题

无法打开 JPA EntityManager 进行事务处理;嵌套异常是 org.hibernate.exception.SQLGrammarException:无法获取 JDBC 连接