首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JOOQ &事务

JOOQ &事务
EN

Stack Overflow用户
提问于 2013-11-18 11:07:58
回答 4查看 20.8K关注 0票数 17

我一直在阅读关于交易与交易的文章,但是我很难看到如何在实践中实现它。

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

执行工作大致如下:

代码语言:javascript
复制
@Override public Connection acquire() throws DataAccessException {
    return pool.getConnection();
}

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

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

使用DefaultConnectionProvider很容易,因为只有一个连接--但是对于一个池,我不知道如何实现它。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-11-18 17:19:12

jOOQ 3.4事务API

在JDBC3.4中,已经在JDBC、jOOQ或JTA事务管理器上添加了事务API。此API可与Java 8一起使用,如下所示:

代码语言:javascript
复制
DSL.using(configuration)
   .transaction(ctx -> {
       DSL.using(ctx)
          .update(TABLE)
          .set(TABLE.COL, newValue)
          .where(...)
          .execute();
   });

或使用预Java 8语法。

代码语言:javascript
复制
DSL.using(configuration)
   .transaction(new TransactionRunnable() {
       @Override
       public void run(Configuration ctx) {
           DSL.using(ctx)
              .update(TABLE)
              .set(TABLE.COL, newValue)
              .where(...)
              .execute();
       }
   });

其思想是lambda表达式(或匿名类)形成事务性代码,该代码:

  • 在正常完成时作出承诺
  • 异常回滚

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

Spring示例

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

  • http://www.jooq.org/doc/latest/manual/getting-started/tutorials/jooq-with-spring/

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

代码语言:javascript
复制
<!-- Using Apache DBCP as a connection pooling library.
     Replace this with your preferred DataSource implementation -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    init-method="createDataSource" destroy-method="close">
    <property name="driverClassName" value="org.h2.Driver" />
    <property name="url" value="jdbc:h2:~/maven-test" />
    <property name="username" value="sa" />
    <property name="password" value="" />
</bean>

<!-- Using Spring JDBC for transaction management -->
<bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

<bean id="transactionAwareDataSource"
    class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
    <constructor-arg ref="dataSource" />
</bean>

<!-- Bridging Spring JDBC data sources to jOOQ's ConnectionProvider -->
<bean class="org.jooq.impl.DataSourceConnectionProvider" 
      name="connectionProvider">
    <constructor-arg ref="transactionAwareDataSource" />
</bean>

在这里可以从GitHub获得一个正在运行的示例:

Spring和Guice示例

虽然我个人不推荐它,但一些用户已经成功地用Guice替换了Spring的DI的一部分,并使用Guice处理事务。对于这个用例,在GitHub上也有一个经过集成测试的运行示例:

票数 23
EN

Stack Overflow用户

发布于 2013-11-18 18:47:39

这可能不是最好的方法,但似乎奏效了。请注意,关闭连接并将其返回到池的不是release,而是commit方法,如果某些代码“忘记”提交.

因此,客户端代码如下:

代码语言:javascript
复制
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:

代码语言:javascript
复制
public class PostgresConnectionProvider implements ConnectionProvider {
    private static final Logger LOG = LoggerFactory.getLogger(PostgresConnectionProvider.class);

    private final ThreadLocal<Connection> 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());
    }
}
票数 5
EN

Stack Overflow用户

发布于 2014-06-24 07:11:45

在这里给出了在jOOQ中使用Spring事务的最简单方法(我已经发现):http://blog.liftoffllc.in/2014/06/jooq-and-transactions.html

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

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

代码语言:javascript
复制
  <bean
   id="dataSource"
   class="org.apache.tomcat.jdbc.pool.DataSource"
   destroy-method="close"

   p:driverClassName="com.mysql.jdbc.Driver"
   p:url="mysql://locahost:3306/db_name"
   p:username="root"
   p:password="root"
   p:initialSize="2"
   p:maxActive="10"
   p:maxIdle="5"
   p:minIdle="2"
   p:testOnBorrow="true"
   p:validationQuery="/* ping */ SELECT 1"
  />

  <!-- Configure the PlatformTransactionManager bean -->
  <bean
   id="transactionManager"
   class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
   p:dataSource-ref="dataSource"
  />
  <!-- Scan for the Transactional annotation -->
  <tx:annotation-driven/>

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

代码语言:javascript
复制
@Transactional(rollbackFor = Exception.class)

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

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20046247

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档