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创建的事务。