首先,我不能使用声明性@Transactional
方法,因为应用程序有多个JDBC数据源,我不想厌倦细节,但足以说DAO方法通过了正确的数据源来执行逻辑。所有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;
}
好的,我知道很多锅炉。所以我试过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需要根据提供的参数在运行时确定使用哪个数据源,在我的例子中是国家代码。
非常感谢任何帮助。
答案 0 :(得分:1)
使用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方法(这应该会大大清理您的代码)。
答案 1 :(得分:0)
我目前通过直接使用DataSourceTransactionManager
来解决这个问题,虽然看起来我没有像我最初希望的那样节省多少锅炉。不要误解我,它更干净,虽然我仍然无法帮助,但我觉得必须有一个更简单的方法。我不需要读取事务,我只想设置隔离。
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
答案 2 :(得分:0)
定义代理数据源,类为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>