将 JOOQ 查询与 JDBC 事务混合
Posted
技术标签:
【中文标题】将 JOOQ 查询与 JDBC 事务混合【英文标题】:Mix JOOQ query with JDBC transaction 【发布时间】:2021-09-16 08:29:23 【问题描述】:我有一个用例,我想将 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,使用语句非常简单。例如这样的tutorail:
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
?
【问题讨论】:
我不明白你的问题。使用 DSL.using 创建 DslContext 时,您必须将连接传递给配置。并且提交发生在连接上。 我想传递一个语句而不是连接。我已经在使用该语句使用 jdbc 运行其他查询/更新。 很抱歉,您的代码没有意义,因为您只能在每个事务的语句上执行。这将与自动提交相同 除此之外还有一个未解决的问题:github.com/jOOQ/jOOQ/issues/3715 我添加了一个如何使用该方法的示例。同一事务的多个查询中使用相同的语句。 【参考方案1】:您描述的问题的解决方案
您可以使用 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()
方法时,您始终可以访问如上所示的JDBC API。所以,如上图:
旁注
在许多 RDBMS 中,您不希望在静态 JDBC Statement
上运行查询。你会想改用PreparedStatement
,因为:
【讨论】:
【参考方案2】:如果你想从 jOOQ 中获取查询字符串,你可以调用
String sqlString = query.getSQL()
然后在你的语句中使用这个字符串:
stmt.executeUpdate(sqlString);
【讨论】:
谢谢,这是一个很好的更新解决方案。就我而言,我也有查询(jooq 解析结果并创建对象),但我不知道如何使用它。 我会反其道而行之。对所有事情都使用 jOOQ。您还可以将 SQL 字符串传递给 jOOQ 以执行。以上是关于将 JOOQ 查询与 JDBC 事务混合的主要内容,如果未能解决你的问题,请参考以下文章