mixjooq查询与jdbc事务

zzlelutf  于 2021-08-25  发布在  Java
关注(0)|答案(2)|浏览(401)

我有一个用例,我想将jdbc事务与jooq上下文混合使用。
jdbc代码如下所示:

public void inTransaction(InTransaction lambda) {
    DataSource ds = dataSource.get();
    try (Connection connection = ds.getConnection()) {
      try {
        logger.info("set autocommit to false");
        connection.setAutoCommit(false);
        try (Statement statement = connection.createStatement()) {
          lambda.execute(statement);
          logger.info("commiting transaction");
          connection.commit();
        }
      } catch (RuntimeException e) {
        logger.info("rolling back transaction");
        connection.rollback();
        throw e;
      } finally {
        logger.info("set autocommit to true");
        connection.setAutoCommit(true);
      }
    } catch (SQLException e) {
      throw new TilerException(e);
    }
  }

  @FunctionalInterface
  public interface InTransaction {
    void execute(Statement statement) throws SQLException;
  }

我想要 lambda 参数,以便能够同时使用jdbc和jooq。
对于jdbc来说,使用语句非常简单。例如,像这样的图托拉尔:

inTransaction(stmt -> {
   String SQL = "INSERT INTO Employees  " +
                "VALUES (106, 20, 'Rita', 'Tez')";
   stmt.executeUpdate(SQL);
   String SQL = "INSERTED IN Employees  " +
                "VALUES (107, 22, 'Sita', 'Singh')";
   stmt.executeUpdate(SQL);
 });

为了在同一事务上执行jooq查询,我必须获得一个上下文。我找到了一个api来从数据源/连接获取dslcontext。
我不清楚的是是否/如何创建jooq DSLContext 从一份声明中?

kpbwa7wx

kpbwa7wx1#

您描述的问题的解决方案

您可以使用jooq的事务api完成所有这一切:

// Create this ad-hoc, or inject it, or whatever
DSLContext ctx = DSL.using(dataSource, dialect);

然后:

public void inJDBCTransaction(InJDBCTransaction lambda) {
    ctx.transaction(config -> {
        config.dsl().connection(connection -> {
            try (Statement statement = connection.createStatement()) {
                lambda.execute(statement);
            }
        });
    });
}

public void inJOOQTransaction(InJOOQTransaction lambda) {
    ctx.transaction(config -> lambda.execute(config.dsl()));
}

@FunctionalInterface
public interface InJDBCTransaction {
    void execute(Statement statement) throws SQLException;
}

@FunctionalInterface
public interface InJOOQTransaction {
    void execute(DSLContext ctx);
}

您的最终代码:

inJDBCTransaction(stmt -> {
    String SQL = "INSERT INTO Employees  " +
                 "VALUES (106, 20, 'Rita', 'Tez')";
    stmt.executeUpdate(SQL);
    String SQL = "INSERTED IN Employees  " +
                 "VALUES (107, 22, 'Sita', 'Singh')";
    stmt.executeUpdate(SQL);
});

inJOOQTransaction(ctx -> {
    ctx.insertInto(EMPLOYEES).values(106, 20, "Rita", "Tez").execute();
    ctx.insertInto(EMPLOYEES).values(107, 22, "Sita", "Singh").execute();
});

我不太相信对jooq和jdbc进行这种抽象的必要性。jooq从不向您隐藏jdbc。当使用 DSLContext.connection() 方法。因此,如上所示:
jooq事务api正是您计划要做的事情。在事务上下文中 Package lambda,如果成功则提交,如果失败则回滚(您的版本的回滚无法工作,因为它捕获了错误的异常)。
如果需要“jdbc逃生舱”,jooq可以提供

旁注

在许多rdbms中,您不希望在静态jdbc上运行查询 Statement . 你会想用 PreparedStatement 而是因为:
您将从执行计划缓存中获益(并减少缓存上的争用)
您将避免语法错误(如果实际查询是动态的)
这样可以避免sql注入问题

a6b3iqyw

a6b3iqyw2#

如果要从jooq获取查询字符串,可以调用

String sqlString = query.getSQL()

然后在语句中使用此字符串:

stmt.executeUpdate(sqlString);

相关问题