Spring中使用绑定线程连接的事务

时间:2015-05-18 17:42:17

标签: spring jdbc transactions spring-transactions

我想将连接绑定到一个线程,并将该连接用于任何JdbcTemplate调用,以最终提交更改或执行回滚。

我正在从Groovy脚本中声明所有句子,所以我无法控制将调用多少SQL查询,这就是为什么我必须使用此方法而不是TransactionalTemplate或类似的东西。这个脚本将调用一个将使用该连接和JdbcTemplate的帮助器类,让我们调用该类 SqlHelper

现在我的非工作所需解决方案是从groovy脚本调用 SqlHelper 来初始化事务:

initTransaction(ecommerce)

调用

public void initTransaction(DataSource dataSource) {
    DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
    transactionDefinition.setReadOnly(false);
    transactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
    // dataSourceTransactionManager.setDataSource(dataSource);
    // dataSourceTransactionManager.setRollbackOnCommitFailure(true);
    // dataSourceTransactionManager.setTransactionSynchronization(TransactionSynchronization.STATUS_COMMITTED);
    // dataSourceTransactionManager.setDataSource(dataSource);

    try {
        Connection connection = DataSourceUtils.getConnection(dataSource);
        connection.setAutoCommit(false);
        DataSourceUtils.prepareConnectionForTransaction(connection, transactionDefinition);
    } catch (CannotGetJdbcConnectionException e) {
        throw new RuntimeException(e);
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
}

之后,脚本将调用一些SQL操作,如

sqlUpdate(ecommerce, insertSentence, insertParams)

调用

public Integer update(DataSource dataSource, String sql, Map<String, Object> paramMap) {
    return new NamedParameterJdbcTemplate(dataSource).update(sql, paramMap);
}

最后,我想完成使用

提交更改的事务
commitTransaction(dataSource)

调用

public void commitTransaction(DataSource dataSource) {
     Connection connection = DataSourceUtils.getConnection(dataSource);
     try {
     connection.commit();
     } catch (Exception e) {
     rollbackTransaction(dataSource);
     }
    // DataSourceUtils.resetConnectionAfterTransaction(connection, TransactionDefinition.ISOLATION_DEFAULT);
    //        SimpleTransactionStatus transactionStatus = new SimpleTransactionStatus(false);
    //        try {
    //            dataSourceTransactionManager.commit(transactionStatus);
    //            jta.commit(transactionStatus);
    //        } catch (TransactionException e) {
    //             dataSourceTransactionManager.rollback(transactionStatus);
    //            throw new RuntimeException(e);
    //        }
}

private void rollbackTransaction(DataSource dataSource) {
    Connection connection = DataSourceUtils.getConnection(dataSource);
    try {
        connection.rollback();
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
    DataSourceUtils.resetConnectionAfterTransaction(connection, TransactionDefinition.ISOLATION_DEFAULT);
}

我留下了一些测试的评论块,向您展示我尝试过的方法。我不太清楚Spring的交易是如何运作的,所以我只是尝试不同的东西并试图了解所有这些东西是如何工作的...如果你愿意,我会为你提供更多信息;)

提前谢谢。

更新

正如M. Denium所说,这就是我现在所拥有的:

我使用TransactionStatus作为ThreadSafe声明了变量,并最终解决为:

private DataSourceTransactionManager dataSourceTransactionManager = null;
private DefaultTransactionDefinition transactionDefinition = null;
private static final ThreadLocal<TransactionStatus> transactionStatus = new ThreadLocal<TransactionStatus>() {
    @Override
    protected TransactionStatus initialValue() {
        return null;
    }
};

然后使用来自Groovy脚本的相同调用,使用辅助方法:

public void initTransaction(DataSource dataSource) {
    dataSourceTransactionManager = new DataSourceTransactionManager();
    transactionDefinition = new DefaultTransactionDefinition();
    transactionDefinition.setReadOnly(false);
    transactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
    dataSourceTransactionManager.setRollbackOnCommitFailure(true);
    dataSourceTransactionManager.setTransactionSynchronization(TransactionSynchronization.STATUS_UNKNOWN);
    dataSourceTransactionManager.setDataSource(dataSource);
    transactionStatus.set(dataSourceTransactionManager.getTransaction(null));
}

public void commitTransaction() {
    try {
        LOG.info("Finishing transaction...");
        dataSourceTransactionManager.commit(transactionStatus.get());
        dataSourceTransactionManager.getDataSource().getConnection().close();
        LOG.info("Done.");
    } catch (Throwable e) {
        dataSourceTransactionManager.rollback(transactionStatus.get());
        throw new RuntimeException("An exception during transaction. Rolling back.");
    }
}

1 个答案:

答案 0 :(得分:2)

您正在尝试重新实现Spring的事务抽象已经实现的内容。只需使用正确的PlatformTransactionManager(您可以从ApplicationContext获取)保留对TransactionStatus的引用而不是DataSource,并使用它来提交/回滚。< / p>

public TransactionStatus initTransaction() {
    return transactionManager.getTransaction(null);
}

public void commit(TransactionStatus status) {
    transactionManager.commit(status);
}

除了传递TransactionStatus之外,您还可以将其存储在ThreadLocal中,并使用commit方法检索它。这样可以缓解疼痛。

另一个提示你不应该创建JdbcTemplateNamedParameterJdbcTemplate这些是要创建的重物。在构建时,他们会查询连接以确定异常转换所需的数据库和版本。因此,性能明智,这不是一件明智的事情。创建单个实例并重用,模板是线程安全的,因此您只需要一个实例。

但是我坚决认为你应该使用Groovy而不是试图解决它。 Groovy有Sql类可以帮助你。您已经可以访问DataSource,因此只需执行此操作即可。

def sql = new Sql(dataSource);
sql.withTransaction {
    sql.execute "INSERT INTO city (name, state, founded_year) VALUES ('Minneapolis', 'Minnesota', 1867)"
    sql.execute "INSERT INTO city (name, state, founded_year) VALUES ('Orlando', 'Florida', 1875)"
    sql.execute "INSERT INTO city (name, state, founded_year) VALUES ('Gulfport', 'Mississippi', 1887)"
}

这是普通的Groovy,无需开发其他类或编写大量文档来使其正常工作。只是Groovy ......