JOOQ和交易

我一直在阅读有关交易和jooq的内容,但我很难看到如何在实践中实现它。

假设我使用自定义ConnectionProvider提供JOOQ,它恰好使用自动提交设置为false的连接池。

实施大致如下:

 @Override public Connection acquire() throws DataAccessException { return pool.getConnection(); } @Override public void release(Connection connection) throws DataAccessException { connection.commit(); connection.close(); } 

我如何将两个jooq查询包装到单个事务中?

使用DefaultConnectionProvider很容易,因为只有一个连接 – 但是对于一个池我不知道如何去做。

jOOQ 3.4交易API

使用jOOQ 3.4,添加了一个事务API来抽象JDBC,Spring或JTA事务管理器。 此API可以与Java 8一起使用:

 DSL.using(configuration) .transaction(ctx -> { DSL.using(ctx) .update(TABLE) .set(TABLE.COL, newValue) .where(...) .execute(); }); 

或者使用pre-Java 8语法

 DSL.using(configuration) .transaction(new TransactionRunnable() { @Override public void run(Configuration ctx) { DSL.using(ctx) .update(TABLE) .set(TABLE.COL, newValue) .where(...) .execute(); } }); 

想法是lambda表达式(或匿名类)构成事务代码,其中:

  • 正常完成后提交
  • 回滚例外

org.jooq.TransactionProvider SPI可用于覆盖默认行为,该行为使用Savepoints通过JDBC实现可嵌套事务。

一个spring的例子

当前文档显示了使用Spring进行事务处理时的示例:

这个例子基本上归结为使用Spring TransactionAwareDataSourceProxy

                   

GitHub提供了一个运行示例:

一个Spring和Guice的例子

虽然我个人不会推荐它,但有些用户已经成功取代了Guice的Spring的DI部分,并处理了与Guice的交易。 在GitHub上还有针对此用例的集成测试运行示例:

这可能不是最好的方式,但似乎有效。 需要注意的是,它不是release而是关闭连接并将其返回到池的commit方法,这非常令人困惑,如果某些代码“忘记”提交,可能会导致问题…

所以客户端代码看起来像:

 final PostgresConnectionProvider postgres = new PostgresConnectionProvider("localhost", 5432, params.getDbName(), params.getUser(), params.getPass()) private static DSLContext sql = DSL.using(postgres, SQLDialect.POSTGRES, settings); //execute some statements here sql.execute(...); //and don't forget to commit or the connection will not be returned to the pool PostgresConnectionProvider p = (PostgresConnectionProvider) sql.configuration().connectionProvider(); p.commit(); 

和ConnectionProvider:

 public class PostgresConnectionProvider implements ConnectionProvider { private static final Logger LOG = LoggerFactory.getLogger(PostgresConnectionProvider.class); private final ThreadLocal connections = new ThreadLocal<>(); private final BoneCP pool; public PostgresConnectionProvider(String serverName, int port, String schema, String user, String password) throws SQLException { this.pool = new ConnectionPool(getConnectionString(serverName, port, schema), user, password).pool; } private String getConnectionString(String serverName, int port, String schema) { return "jdbc:postgresql://" + serverName + ":" + port + "/" + schema; } public void close() { pool.shutdown(); } public void commit() { LOG.debug("Committing transaction in {}", Thread.currentThread()); try { Connection connection = connections.get(); if (connection != null) { connection.commit(); connection.close(); connections.set(null); } } catch (SQLException ex) { throw new DataAccessException("Could not commit transaction in postgres pool", ex); } } @Override public Connection acquire() throws DataAccessException { LOG.debug("Acquiring connection in {}", Thread.currentThread()); try { Connection connection = connections.get(); if (connection == null) { connection = pool.getConnection(); connection.setAutoCommit(false); connections.set(connection); } return connection; } catch (SQLException ex) { throw new DataAccessException("Can't acquire connection from postgres pool", ex); } } @Override //no-op => the connection won't be released until it is commited public void release(Connection connection) throws DataAccessException { LOG.debug("Releasing connection in {}", Thread.currentThread()); } } 

最简单的方法,(我发现)使用jOOQ的Spring Transactions,这里给出: http ://blog.liftoffllc.in/2014/06/jooq-and-transactions.html

基本上我们实现了一个ConnectionProvider ,它使用org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(ds)方法来查找并返回保存Spring创建的事务的数据库连接。

为您的DataSource创建一个TransactionManager bean,如下所示:

       

现在,您可以注释使用jOOQ的DSLContext所有类或方法

 @Transactional(rollbackFor = Exception.class) 

在创建DSLContext对象时,jOOQ将使用Spring创建的事务。