[英]Spring Transactional annotation, isolation not working for READ_UNCOMMITTED
[英]How can I get a spring JdbcTemplate to read_uncommitted?
首先,我不能使用聲明性@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;
}
好吧,很多樣板,我知道。 所以自從我使用 spring 以來,我已經嘗試了JdbcTemplate
。
使用 Jdbc 模板
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 需要在運行時根據提供的參數使用哪個數據源,在我的例子中是國家/地區代碼。
任何幫助將不勝感激。
我目前已經通過直接使用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;
}
我仍然會暫時不回答這個問題,因為我真的相信一定有更好的方法。
在這里使用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 代碼,這些代碼基本上在需要時切換數據源。 可以在此處找到更多信息。
如果這對您的應用程序來說過於牽強或矯枉過正,您還可以嘗試使用 Spring 的AbstractRoutingDataSource
,它基於查找鍵(在您的情況下為國家/地區代碼)選擇要使用的正確數據源。
通過使用這兩種解決方案中的任何一種,您都可以開始使用 springs 聲明式事務管理方法(這應該可以大大清理您的代碼)。
定義一個代理數據源,類為 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>
我不確定您是否可以在不使用 Spring 提供的“事務性”抽象級別的情況下做到這一點。
構建您的 transactionTemplate 的更多“無 xml”可能是這樣的。
private TransactionTemplate getTransactionTemplate(String executionTenantCode, boolean readOnlyTransaction) {
TransactionTemplate tt = new TransactionTemplate(transactionManager);
tt.setReadOnly(readOnlyTransaction);
tt.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
return tt;
}
在任何情況下,我都會“利用” @Transactional
注釋指定適當的事務管理器,綁定到一個單獨的數據源。 我已經為多租戶應用程序完成了這項工作。
用法:
@Transactional(transactionManager = CATALOG_TRANSACTION_MANAGER,
isolation = Isolation.READ_UNCOMMITTED,
readOnly = true)
public void myMethod() {
//....
}
bean(s) 聲明:
public class CatalogDataSourceConfiguration {
@Bean(name = "catalogDataSource")
@ConfigurationProperties("catalog.datasource")
public DataSource catalogDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = ENTITY_MANAGER_FACTORY)
public EntityManagerFactory entityManagerFactory(
@Qualifier("catalogEntityManagerFactoryBean") LocalContainerEntityManagerFactoryBean emFactoryBean) {
return emFactoryBean.getObject();
}
@Bean(name= CATALOG_TRANSACTION_MANAGER)
public PlatformTransactionManager catalogTM(@Qualifier(ENTITY_MANAGER_FACTORY) EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
@Bean
public NamedParameterJdbcTemplate catalogJdbcTemplate() {
return new NamedParameterJdbcTemplate(catalogDataSource());
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.