2012-03-21 62 views
6

我有一個基於Spring的JdbcTemplate道下面的代碼 -如何在Spring中對兩個查詢使用相同的連接?

getJdbcTemplate().update("Record Insert Query..."); 
int recordId = getJdbcTemplate().queryForInt("SELECT last_insert_id()"); 

的問題是,我有時我的更新和queryForInt查詢開始使用連接池中的不同連接執行。

這會導致返回不正確的recordId,因爲MySql last_insert_id()應該從發出插入查詢的同一個連接調用。

我已經考慮過SingleConnectionDataSource,但不想使用它,因爲它降低了應用程序的性能。我只想要這兩個查詢的單一連接。並非針對所有服務的所有請求。

所以我有兩個問題:

  1. 我可以管理模板類使用的連接?
  2. JdbcTemplate是否執行自動事務管理?如果我手動將事務應用於我的Dao方法,是否意味着每個查詢都會創建兩個事務?

希望你們可以對這個話題有所瞭解。

更新 - 我試過nwinkler的方法,並在事務中包裹了我的服務層。我很驚訝地發現在某個時間之後再次出現同樣的問題。挖成春源代碼,我發現這一點 -

public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action) 
throws DataAccessException { 
//Lots of code 
Connection con = DataSourceUtils.getConnection(getDataSource()); 
//Lots of code 
} 

所以相反的是我想,有沒有必要每個事務的數據庫連接,但對於執行的每個查詢的一個連接。 這使我回到我的問題。我想從同一個連接執行兩個查詢。 :-(

更新 -

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 
     destroy-method="close"> 
     <property name="driverClassName" value="${db.driver}" /> 
     <property name="url" value="${db.jdbc.url}" /> 
     <property name="username" value="${db.user}" /> 
     <property name="password" value="${db.password}" /> 
     <property name="maxActive" value="${db.max.active}" /> 
     <property name="initialSize" value="20" /> 
    </bean> 

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" 
     autowire="byName"> 
     <property name="dataSource"> 
      <ref local="dataSource" /> 
     </property> 
    </bean> 


    <bean id="transactionManager" 
     class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
     <property name="dataSource" ref="dataSource" /> 
    </bean> 

    <tx:advice id="transactionAdvice" transaction-manager="transactionManager"> 
     <tx:attributes> 
      <tx:method name="*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception" timeout="30" /> 
     </tx:attributes> 
    </tx:advice> 
    <aop:config> 
     <aop:pointcut id="pointcut" expression="execution(* service.*.*(..))" /> 
     <aop:pointcut id="pointcut2" expression="execution(* *.ws.*.*(..))" /> 

     <aop:advisor pointcut-ref="pointcut" advice-ref="transactionAdvice" /> 
     <aop:advisor pointcut-ref="pointcut2" advice-ref="transactionAdvice" /> 
    </aop:config> 
+0

嗯,那麼我想你還在做錯事。你可以發佈你的Spring配置,包括數據源和事務管理嗎? Spring的片段來自哪個類?你在哪裏找到這個? – nwinkler 2012-04-01 09:13:45

+0

該代碼來自JdbcTemplate類。每當執行查詢時調用它,因此我懷疑。 – 2012-04-02 04:08:28

+0

請看看我更新的答案... – nwinkler 2012-04-02 06:22:56

回答

9

確保您的DAO被包裹在一個事務(例如,通過使用Spring的攔截器進行交易)相同的連接將被用於兩個電話

更妙的是有一個交易水平高,業務層

文檔:http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html

更新: 如果你看看您在更新引用的DataSourceUtils.getConnection()方法的JavaDoc,你會看到,它獲得與當前線程相關的連接:

是知道的綁定到當前線程的相應Connection,例如使用{@link DataSourceTransactionManager}時的 。如果事務同步處於活動狀態,將綁定連接至 線程,例如當在一個 {@link org.springframework.transaction.jta.JtaTransactionManager JTA}事務中運行時)。

據此,它應該像你設置它一樣工作。我已經使用這個模式很多次,從來沒有跑進描述像你的任何問題......

也請看一看這個線程,有人在處理類似問題有:Spring Jdbc declarative transactions created but not doing anything

+0

這沒有任何併發​​問題嗎?服務的多次調用仍然使用不同的事務,因此使用不同的連接。對? – 2012-03-21 17:04:17

+0

確切地說,這就是在服務層使用事務分界的關鍵。每個服務調用都將在其自己的事務中運行,並將使用專用的數據庫連接。一旦事務被提交或回滾,連接就會返回到池中,並可用於下一個事務。 – nwinkler 2012-03-21 17:07:53

+0

非常感謝。通過大量的文檔保存了我:-) – 2012-03-21 17:26:43

0

這是我的方法來做到這一點:

namedJdbcTemplate.execute(savedQuery, map, new PreparedStatementCallback<Object>() { 
      @Override 
      public Object doInPreparedStatement(PreparedStatement paramPreparedStatement) 
        throws SQLException, DataAccessException { 
       paramPreparedStatement.execute("SET @userLogin = 'blabla123'"); 
       paramPreparedStatement.executeUpdate(); 
       return null; 
      } 
     }); 
相關問題