2012-03-21 36 views
6

Tôi có đoạn mã sau vào ả đào mùa xuân JdbcTemplate dựa -Làm thế nào để sử dụng cùng một kết nối cho hai truy vấn trong Spring?

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

Vấn đề là tôi thỉnh thoảng cập nhật của tôi và truy vấn queryForInt được thực hiện sử dụng các kết nối khác nhau từ hồ bơi kết nối.

Kết quả này trong một bản ghi không chính xácId được trả về vì MySql last_insert_id() được cho là được gọi từ cùng một kết nối đã đưa ra truy vấn chèn.

Tôi đã xem xét SingleConnectionDataSource nhưng không muốn sử dụng nó vì nó làm giảm hiệu suất của ứng dụng. Tôi chỉ muốn kết nối duy nhất cho hai truy vấn này. Không phải cho tất cả các yêu cầu cho tất cả các dịch vụ.

Vì vậy, tôi có hai câu hỏi:

  1. Tôi có thể quản lý các kết nối sử dụng bởi các lớp mẫu?
  2. JdbcTemplate có thực hiện quản lý giao dịch tự động không? Nếu tôi tự áp dụng một giao dịch cho phương thức Dao của tôi thì điều đó có nghĩa là hai giao dịch sẽ được tạo cho mỗi truy vấn?

Hy vọng rằng các bạn có thể làm sáng tỏ chủ đề.

Cập nhật - Tôi đã thử cách tiếp cận của nwinkler và gói lớp dịch vụ của tôi trong giao dịch. Tôi đã rất ngạc nhiên khi thấy cùng một lỗi xuất hiện trở lại sau một thời gian. Đào vào mã nguồn mùa xuân tôi thấy điều này -

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

Vì vậy, trái với những gì tôi nghĩ, không nhất thiết phải là một kết nối cơ sở dữ liệu cho mỗi giao dịch, nhưng một kết nối cho mỗi truy vấn thực hiện. Điều này đưa tôi trở lại vấn đề của tôi. Tôi muốn thực hiện hai truy vấn từ cùng một kết nối. :-(

Cập nhật -

<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

Mh, sau đó tôi đoán bạn vẫn đang làm điều gì sai. Bạn có thể vui lòng đăng cấu hình Spring của mình, bao gồm cả quản lý dữ liệu và quản lý giao dịch không? Lớp nào là đoạn trích Spring từ đó? Bạn tìm thấy cái này ở đâu? – nwinkler

+0

Mã đó là từ lớp JdbcTemplate. Nó được gọi là bất cứ khi nào một truy vấn được thực hiện, do đó tôi nghi ngờ. –

+0

Hãy xem câu trả lời cập nhật của tôi ... – nwinkler

Trả lời

9

Hãy chắc chắn rằng DAO của bạn được bao bọc trong một giao dịch (ví dụ như bằng cách sử dụng đánh chặn Spring cho giao dịch) Kết nối cùng sau đó sẽ được sử dụng cho cả cuộc gọi

..

Thậm chí tốt hơn là nên có các giao dịch một mức độ cao hơn, tại các lớp dịch vụ

Tài liệu:. http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html

Cập nhật: Nếu bạn có một cái nhìn tại javadoc của DataSourceUtils.getConnection() phương pháp mà bạn tham chiếu trong bản cập nhật của bạn, bạn sẽ thấy rằng nó có được kết nối liên quan đến các chủ đề hiện tại:

là nhận thức một kết nối tương ứng được liên kết với luồng hiện tại, ví dụ: khi sử dụng {@link DataSourceTransactionManager}. Sẽ liên kết một Kết nối với chuỗi nếu đồng bộ hóa giao dịch đang hoạt động, ví dụ: khi chạy trong giao dịch {@link org.springframework.transaction.jta.JtaTransactionManager JTA}).

Theo đó, nó sẽ hoạt động như bạn đã thiết lập. Tôi đã sử dụng mô hình này rất nhiều lần, và không bao giờ chạy vào bất kỳ vấn đề như bạn mô tả ...

Xin hãy nhìn vào chủ đề này, có ai đó đang đối phó với vấn đề tương tự có: Spring Jdbc declarative transactions created but not doing anything

+0

Điều này không có bất kỳ vấn đề tương tranh nào không? Nhiều lời gọi của dịch vụ sẽ vẫn sử dụng các giao dịch khác nhau và do đó các kết nối khác nhau. Đúng? –

+0

Chính xác, đó là toàn bộ điểm sử dụng phân giới giao dịch tại tầng dịch vụ. Mỗi cuộc gọi dịch vụ sẽ chạy trong giao dịch của riêng nó và sẽ sử dụng một kết nối cơ sở dữ liệu chuyên dụng. Sau khi giao dịch được thực hiện hoặc quay trở lại, kết nối được trả về hồ bơi và có thể được sử dụng trong giao dịch tiếp theo. – nwinkler

+0

Cảm ơn rất nhiều. Lưu tôi đi qua rất nhiều tài liệu :-) –

0

Đây là của tôi cách tiếp cận để thực hiện việc này:

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; 
      } 
     }); 
Các vấn đề liên quan