【问题标题】:Transaction is not rolled back in JOOQ事务在 JOOQ 中不回滚
【发布时间】:2017-08-19 00:17:18
【问题描述】:

我有一个和这个非常相似的代码:

dslContext.transaction(new TransactionalRunnable()
{
    @Override
    public void run(Configuration arg0) throws Exception
    {
        dao1.insert(object1);
        //Object 1 is inserted in the database 
        //despite the exception that is being thrown
        if(true)
           throw new RuntimeException();
        dao2.insert(object2)
    }
});

这是我用来创建 dsl 上下文和使用 JOOQ 生成的 daos 的代码。

ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setDriverClass(org.postgresql.Driver.class.getName());
comboPooledDataSource.setJdbcUrl("jdbc:postgresql://localhost:5432/database?searchpath=schema");
comboPooledDataSource.setUser("user");
comboPooledDataSource.setPassword("password");
comboPooledDataSource.setMinPoolSize(5);
comboPooledDataSource.setAcquireIncrement(5);
comboPooledDataSource.setMaxPoolSize(25);
Configuration configuration=new DefaultConfiguration().set(comboPooledDataSource).set(
                        SQLDialect.POSTGRES);
DSLContext dslContext=DSL.using(configuration);
Dao1 dao1=new Dao1(configuration);
Dao2 dao2=new Dao2(configuration);

为什么我会出现这种行为?

【问题讨论】:

  • I have a code that is very similar to this one:,当您运行发布的代码时,您的行为是否相同?
  • 您使用的是什么 jOOQ 版本?您能说明一下您的comboPooledDataSource 是如何配置的吗?
  • @LukasEder 我正在使用 3.9.1 版的 JOOQ,我已经更新了问题。

标签: java jooq


【解决方案1】:

您的DAOs 配置了与您的交易不同的配置。这意味着每个 DAO 在新的自动提交事务中运行其代码,即使您将该逻辑放在 TransactionalRunnable 中。

这可行:

dslContext.transaction(new TransactionalRunnable()
{
    @Override
    public void run(Configuration arg0) throws Exception
    {
        new Dao1(arg0).insert(object1);
        if(true)
           throw new RuntimeException();
        new Dao2(arg0).insert(object2)
    }
});

请注意,[DSLContext.transaction(TransactionalRunnable][1]) 不会修改dslContext 及其封闭的Configuration。这意味着如果您的数据源不工作,例如像 JavaEE 或 Spring TransactionAwareDataSourceProxy,那么您必须使用 run() 方法的参数 Configuration 来运行进一步的查询,或者用 DSL.using(configuration) 包装它,或者将它传递给您的道。

更简单的选择是使用事务感知的数据源(即将事务绑定到线程),这样同一个线程将始终从数据源获得相同的事务处理 JDBC Connection

【讨论】:

    【解决方案2】:

    我让 spring 处理 jOOQ 的事务。方法如下:

    这是spring配置类:

    @Configuration
    public class SpringConfiguration
    {
        @Bean
        public DataSource dataSource() throws PropertyVetoException
        {
            comboPooledDataSource.setDriverClass(org.postgresql.Driver.class.getName());
            comboPooledDataSource
                        .setJdbcUrl("jdbc:postgresql://localhost:5432/database?searchpath=schema");
            comboPooledDataSource.setUser("databaseuser");
            comboPooledDataSource.setPassword("password");
    
            comboPooledDataSource.setMinPoolSize(5);
            comboPooledDataSource.setAcquireIncrement(5);
            comboPooledDataSource.setMaxPoolSize(25);
            return comboPooledDataSource;
        }
    
        @Bean
        public DataSourceTransactionManager transactionManager() throws PropertyVetoException
        {
            return new DataSourceTransactionManager(dataSource());
        }
    
        @Bean
        public TransactionAwareDataSourceProxy transactionAwareDataSource() throws PropertyVetoException
        {
            return new TransactionAwareDataSourceProxy(dataSource());
        }
    
        @Bean
        public DataSourceConnectionProvider connectionProvider() throws PropertyVetoException
        {
            return new DataSourceConnectionProvider(transactionAwareDataSource());
        }
    
        @Bean
        public org.jooq.Configuration configuration() throws PropertyVetoException
        {
            return new DefaultConfiguration().set(connectionProvider()).set(transactionProvider()).set(SQLDialect.POSTGRES);
        }
    
        @Bean
        public TransactionProvider transactionProvider() throws PropertyVetoException
        {
            return new SpringTransactionProvider(transactionManager());
        }
    
        @Bean
        public DSLContext dslContext() throws PropertyVetoException
        {
            return DSL.using(configuration());
        }
    } 
    

    这是SpringTransactionProvider

    public class SpringTransactionProvider implements TransactionProvider
    {
        DataSourceTransactionManager transactionManager;
    
        public SpringTransactionProvider(DataSourceTransactionManager transactionManager)
        {
            this.transactionManager = transactionManager;
        }
    
        @Override
        public void begin(TransactionContext ctx)
        {
            TransactionStatus tx = transactionManager.getTransaction(new DefaultTransactionDefinition(
                    TransactionDefinition.PROPAGATION_REQUIRED));
            ctx.transaction(new SpringTransaction(tx));
        }
    
        @Override
        public void commit(TransactionContext ctx)
        {
            transactionManager.commit(((SpringTransaction) ctx.transaction()).tx);
        }
    
        @Override
        public void rollback(TransactionContext ctx)
        {
            transactionManager.rollback(((SpringTransaction) ctx.transaction()).tx);
        }
    
        class SpringTransaction implements Transaction
        {
            final TransactionStatus tx;
    
            SpringTransaction(TransactionStatus tx)
            {
                this.tx = tx;
            }
        }
    }
    

    最后得到DSLContext

    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
    DSLContext dslContext=applicationContext.getBean(DSLContext.class);
    

    你需要在你的类路径中使用这些 jar 来让它工作: spring-tx.jarspring-aop.jarspring-expression.jarspring-core.jarspring-beans.jarspring-jdbc.jarspring-context.jar :)

    【讨论】:

      猜你喜欢
      • 2013-02-16
      • 2012-11-04
      • 2018-11-17
      • 2011-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-13
      相关资源
      最近更新 更多