首页 文章

如何获得一个spring JdbcTemplate来read_uncommitted?

提问于
浏览
1

首先,我不能使用声明性的 @Transactional 方法,因为应用程序有多个JDBC数据源,因为我暴露了ERP系统的休息服务,所以我不会分开 .

由于这个遗留系统有很多长期存在的锁定记录,我无法控制,所以我想要脏读 .

使用JDBC我会执行以下操作:

private Customer getCustomer(DataSource ds, String id) {
    Customer c = null;
    PreparedStatement stmt = null;
    Connection con = null;
    try {
        con = ds.getConnection();
        con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
        stmt = con.prepareStatement(SELECT_CUSTOMER);
        stmt.setString(1, id);
        ResultSet res = stmt.executeQuery();
        c = buildCustomer(res);
    } catch (SQLException ex) {
        // log errors
    } finally {
        // Close resources
    }
    return c;
}

好吧,很多' of boiler-plate, I know. So I'已经尝试了 JdbcTemplate ,因为我正在使用spring .

使用JdbcTemplate

private Customer getCustomer(JdbcTemplate t, String id) {
    return t.queryForObject(SELECT_CUSTOMER, new CustomerRowMapper(), id);
}

更好,但它仍然使用默认事务隔离 . 我需要以某种方式改变这一点 . 所以我想到了使用 TransactionTemplate .

private Customer getCustomer(final TransactionTemplate tt,
                             final JdbcTemplate t,
                             final String id) {
    return tt.execute(new TransactionCallback<Customer>() {
        @Override
        public Customer doInTransaction(TransactionStatus ts) {
            return t.queryForObject(SELECT_CUSTOMER, new CustomerRowMapper(), id);
        }
    });
}

但是如何在此处设置事务隔离?我无法在回调的任何地方找到它或 TransactionTemplate 来做到这一点 .

我正在阅读Spring in Action,第三版,它解释了我已经完成的事情,尽管关于事务的章节继续使用带注释的声明式事务,但如上所述我不能使用它,因为我的DAO需要确定运行时基于提供的参数使用的数据源,在我的例子中是国家代码 .

任何帮助将不胜感激 .

3 回答

  • 0

    使用 TransactionTemplate 可以帮助您,您需要适当地配置它 . 事务模板还包含事务配置 . 实际上 TransactionTemplate 延伸 DefaultTransactionDefinition .

    所以在你的配置中你应该有这样的东西 .

    <bean id="txTemplate" class=" org.springframework.transaction.support.TransactionTemplate">
      <property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>
      <property name="readOnly" value="true" />
      <property name="transactionManager" ref="transactionManager" />
    </bean>
    

    如果您随后将此bean注入您的类,您应该能够使用之前发布/尝试过的基于 TransactionTemplate 的代码 .

    但是,可能有一个更好的解决方案可以清理您的代码 . 对于我参与的其中一个项目,我们有与您相似的设置(单个应用程序多个数据库) . 为此我们写了一些spring代码,它基本上在需要时切换数据源 . 更多信息可以在here找到 .

    如果你的应用程序是远程提取或过度杀戮,你也可以尝试使用Spring的AbstractRoutingDataSource,它基于查找键(在你的例子中是国家代码)选择要使用的正确数据源 .

    通过使用这两种解决方案中的任何一种,您都可以开始使用spring declarative transactionmanagement方法(这应该会大大清理您的代码) .

  • 0

    我目前通过直接使用_1373350解决了这个问题,虽然看起来好像我错了,但是我觉得必须有一个更简单的方法 . 我不需要读取事务,我只想设置隔离 .

    private Customer getCustomer(final DataSourceTransactionManager txMan,
                                 final JdbcTemplate t,
                                 final String id) {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
    
        TransactionStatus status = txMan.getTransaction(def);
        Customer c = null;
        try {
            c = t.queryForObject(SELECT_CUSTOMER, new CustomerRowMapper(), id);
        } catch (Exception ex) {
            txMan.rollback(status);
            throw ex;
        }
        txMan.commit(status);
        return c;
    }
    

    我仍然会在一段时间内保持这一点,因为我真的相信必须有更好的方法 .

    参考Spring 3.1.x Documentation - Chapter 11 - Transaction Management

  • 1

    定义代理数据源,类为org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy并设置事务隔离级别 . 通过setter或构造函数注入实际数据源 .

    <bean id="yourDataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
        <constructor-arg index="0" ref="targetDataSource"/>
        <property name="defaultTransactionIsolationName" value="TRANSACTION_READ_UNCOMMITTED"/>
    </bean>
    

相关问题