【问题标题】:What happens outside of transaction blocks?交易块之外会发生什么?
【发布时间】:2020-01-04 15:59:15
【问题描述】:

JOOQ Transaction Management 文档在细节上略显简明。请帮我理解以下4种情况的区别:

DSLContext outer = DSL.using(jdbcConnection, SQLDialect.POSTGRES);

// case 1
outer.insertInto(someTable).set(...).execute();

outer.transaction(transactional ->
{
    DSLContext inner = DSL.using(transactional);

    // case 2
    outer.insertInto(someTable).set(...).execute();

    // case 3
    inner.insertInto(someTable).set(...).execute();

    inner.transaction(transactional2 ->
    {
      DSLContext inner2 = DSL.using(transactional2);

      // case 4
      inner2.insertInto(someTable).set(...).execute();
    }
});

我的猜测是:

  • 案例 1 针对自动提交事务运行。
  • 案例 2 与案例 1 相同,尽管它位于 TransactionalRunnable 块内,因为它不使用 transactional
  • 案例 3 针对不自动提交且独立于案例 1 或 2 使用的事务的事务运行。
  • 案例 4 针对不自动提交的事务运行,并且嵌套在案例 3 使用的事务中。

这对吗?

【问题讨论】:

    标签: java sql jooq


    【解决方案1】:

    默认情况下,jOOQ 不管理您的交易,甚至不关心您的交易。所以:

    • 案例 1 使用您在 jOOQ 之外指定的任何事务管理运行,包括例如JDBC 的自动提交标志,默认情况下可能打开也可能不打开。如果您没有任何外部事务管理(例如 Spring),那么您可能是对的,因为大多数驱动程序默认为 autocommit = true。
    • 案例 2 将 JDBC 自动提交标志设置为 false 以执行接收 transactional 参数的 lambda,并将其设置回 lambda 之前的状态。由于您的outer 和您的transactional 最终都在同一个jdbcConnection 上运行,因此案例2 与案例1 相同。它也会“意外”在同一个jOOQ 中运行-托管事务。如果您已将DataSource 传递给outer,那么就有可能实现您所描述的行为(见下文)。
    • 案例 3 独立于案例 1 中的事务,但会与案例 2“意外”在同一事务中运行。
    • 案例4确实是transactional定义的事务的嵌套事务

    我可以从您的代码示例中看到案例 2 似乎令人困惑,但如果您考虑一下 jOOQ 的 TransactionProviderConnectionProvider SPI 的交互方式,它确实是有道理的:

    • ConnectionProvider 为 jOOQ 提供 JDBC 连接以执行单个查询。
      • 如果你给 jOOQ 传递了一个Connection,那么它会被包裹在DefaultConnectionProvider 中,它总是会再次生成相同的 JDBC Connection。在您的案例 2 中,jOOQ 无法生成独立于您当前正在运行的事务的新 JDBC Connection,因为在 JDBC 中,Connection 一次只能有一个事务。
      • 如果你通过 jOOQ 一个DataSource,那么它被包裹在DataSourceConnectionProvider 中。现在,DataSource 可以选择为 jOOQ 提供一个新的 JDBC Connection,这取决于是否已经有事务在进行。在这种情况下,可以使用适当的 TransactionProvider 来实现您的案例 2
    • 每当您调用 jOOQ 的各种 DSLContext::transaction 方法之一时,TransactionProvider 都会管理事务生命周期。它确保您的 lambda 的 DSLContext 参数将不再查询您的 ConnectionProvider 以获取连接,而是将其存储在内部,并确保您将继续使用附加了您的事务的 JDBC Connection。此机制还允许嵌套事务,如您的案例 4。

    换一种说法,如果您在大多数地方都使用 Spring 的 @Transactional 注释,但以某种方式设法访问在 Spring @Transactional 上下文之外的某处初始化的“原始”JDBC Connection,那么您将拥有同样的效果。您还会“意外”继承 @Transactional 上下文。

    【讨论】:

    • 为了澄清,案例 3 旨在在 outer.transaction() 创建的事务中运行。真的是这样吗?
    • @Gili:是的,就是这样。
    猜你喜欢
    • 2018-06-12
    • 1970-01-01
    • 2010-11-02
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2019-01-01
    • 2015-07-17
    • 1970-01-01
    相关资源
    最近更新 更多