2012-07-27 35 views
1

首先,我不能使用聲明@Transactional的方法,因爲應用程序具有多個JDBC數據源,我不想對細節感到厭煩,但可以說DAO方法已將正確的數據源傳遞給執行邏輯。所有JDBC數據源都具有相同的模式,因爲我爲ERP系統公開了其餘服務。如何獲取spring_jdbcTemplate以read_uncommitted?

由於這個遺留系統有很多長期鎖定記錄,我沒有控制,所以我想髒讀。

使用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,因爲我使用的是彈簧。

使用的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

我目前通過直接使用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

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基於代碼/做過這樣的嘗試。

但是,可能有更好的解決方案可以清理你的代碼。對於我所從事的其中一個項目,我們的設置與您的設置類似(單個應用程序多個數據庫)。爲此,我們編寫了一些基本上在需要時切換數據源的彈簧代碼。更多的信息可以在here找到。

如果這對您的應用程序來說太過牽強或過分,您也可以嘗試使用Spring的AbstractRoutingDataSource,它基於查找鍵(您的案例中的國家/地區代碼)選擇要使用的正確數據源。

通過使用這兩種解決方案中的任何一種,您可以開始使用彈簧declarative transactionmanagement方法(應該大大清理您的代碼)。

+0

這是否意味着我需要爲每個數據庫和每個隔離配置多個txTemplate?所以如果我想要6個數據庫的可寫隔離和只讀髒隔離,我需要12個txTemplates? – 2013-08-22 03:57:54

+0

要麼這樣做,要麼在需要時自己構建它們,這將要求您傳入事務管理器並相應地設置配置。我想最好的解決方案是通過使用AbstractRoutingDataSource這種方式來使用Spring聲明式transactionmanagement(並在運行時清理代碼)。 – 2013-08-22 11:09:44

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>