【问题标题】:Spring JDBC's transactions handling doesn't work with Google GuiceSpring JDBC 的事务处理不适用于 Google Guice
【发布时间】:2013-02-09 01:39:32
【问题描述】:

我在我的项目中使用 Google Guice 和 jOOQ。目前我决定使用 Spring JDBC 引入事务处理。

所以我做了以下。

我在 Guice 模块中设置了数据源和事务管理器。

@Provides
@Singleton
DataSource provideDataSource(IExternalSettings settings) {
    Jdbc3PoolingDataSource dataSource = new Jdbc3PoolingDataSource();
    // configuring DataSource
    return dataSource;
}


@Provides
@Singleton
DataSourceTransactionManager provideDataSourceTransactionManager(DataSource dataSource) {
    return new DataSourceTransactionManager(new TransactionAwareDataSourceProxy(dataSource));
}

然后我将我的事务管理器注入持久化外观

@Inject
public PersistenceFacade(final DataSourceTransactionManager transactionManager) {
    this.dataSource = transactionManager.getDataSource();
    this.transactionManager = transactionManager;
}

后来,我用这个数据源创建了jOOQ工厂:new Factory(dataSource, ...)

最后我运行我的数据库访问代码:

DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
TransactionStatus transaction = transactionManager.getTransaction(transactionDefinition);
try {
    // db code in transaction
    transactionManager.commit(transaction);
    return result;
} catch (Exception e) {
    transactionManager.rollback(transaction);
    throw e;
}

到目前为止,一切都很好。它按预期工作

所以,我的下一步是使用 Guice AOP 引入 @Transactional 注释。我创建了一个拦截器

class TransactionalMethodInterceptor implements MethodInterceptor {

    @Inject
    private DataSourceTransactionManager transactionManager;

    @Override
    public Object invoke(final MethodInvocation invocation) throws Throwable {
        DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
        TransactionStatus transaction = transactionManager.getTransaction(transactionDefinition);
        try {
            Object result = invocation.proceed();
            transactionManager.commit(transaction);
            return result;
        } catch (Exception e) {
            transactionManager.rollback(transaction);
            throw e;
        }
    }
}

并在Guice模块的configure()方法中配置:

TransactionalMethodInterceptor transactionalMethodInterceptor = new TransactionalMethodInterceptor();
requestInjection(transactionalMethodInterceptor);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(Transactional.class), transactionalMethodInterceptor);

现在问题开始了。我可以看到,使用调试器,控制流到达拦截器。特别是,它达到了transactionManager.rollback(...) 调用。但事务实际上并未回滚

我不知道是什么原因。有任何想法吗?我会很感激的。谢谢!

【问题讨论】:

  • 调用invocation.proceed()的实例如何获取事务?
  • @AlenVrečko,Interceptor 注入了一个 transactionManager。它使用它来获得新的交易。不确定它是否能回答您的问题?
  • 让我这么说吧,getConnection 在你的事务块中返回相同的连接吗?
  • 我没有明确地打电话给getConnection()。我将数据源传递给 jOOQ 的工厂并获得连接。然而,它在两种情况下都是一样的(即有和没有 AOP)。
  • 导致控制流执行rollback()Exception e是什么?

标签: java transactions guice spring-jdbc jooq


【解决方案1】:

我终于设法回到了这个,我想我找到了解决方案。

首先,我需要提到我引入了一个误解,当我说这一切都可以在没有 AOP 的情况下工作时。今天我无法重现它,我注意到回滚的连接与 jOOQ 使用的连接不同。所以 Alan Vrecko(见上面的评论)是对的!

然后我找到了this answerthis snippet。我决定试一试,它奏效了!但是,之前的所有步骤似乎都是有效的,并且仍然需要存在(包括 Google Guice 的拦截器)。

我必须引入的唯一更改是从SpringExceptionTranslationExecuteListener. exception(ExecuteContext ctx) 中删除DataSourceUtils.releaseConnection(con, dataSource);。所以最后这个方法看起来像

@Override
public void exception(ExecuteContext ctx) {
    SQLException ex = ctx.sqlException();
    Statement stmt = ctx.statement();
    Connection con = ctx.getConnection();
    DataSource dataSource = ctx.getDataSource();
    JdbcUtils.closeStatement(stmt);
    ctx.exception(getExceptionTranslator(dataSource).translate("jOOQ", ctx.sql(), ex));
}

然后似乎一切正常。谢谢大家的cmets。当然,我仍然愿意接受新的/更好的解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-16
    • 1970-01-01
    • 2021-08-02
    相关资源
    最近更新 更多