2012-03-21 10 views
6

У меня есть следующий код в дао основе Spring JdbcTemplate -Как использовать одно соединение для двух запросов весной?

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

Проблема заключается в том, что мой иногда мое обновление и запросы queryForInt получить выполняются с использованием различных соединений из пула соединений.

Это приводит к неправильной записи, возвращаемой с момента вызова MySql last_insert_id() из того же соединения, которое выдало запрос на вставку.

Я рассмотрел источник SingleConnectionDataSource, но не хочу его использовать, так как он ухудшает производительность приложения. Я хочу только одно соединение для этих двух запросов. Не для всех запросов на все услуги.

Поэтому у меня есть два вопроса:

  1. Могу ли я управлять соединением, используемым классом шаблона?
  2. Выполняет ли JdbcTemplate автоматическое управление транзакциями? Если я вручную применяю транзакцию к моему методу Dao, это означает, что для каждого запроса будут созданы две транзакции?

Надеясь, что вы, ребята, можете пролить свет на эту тему.

Обновление - Я пробовал подход nwinkler и завернул свой сервисный уровень в транзакции. Я был удивлен, увидев, как однажды снова появляется такая же ошибка. Копание в исходный код Spring я нашел, что это -

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

Так вопреки тому, что я думал, там не обязательно один подключение к базе данных за одну транзакцию, но одно соединение для каждого запроса выполняется. Что возвращает меня к моей проблеме. Я хочу выполнить два запроса из одного и того же соединения. :-(

Update -

<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, тогда, я думаю, вы все еще делаете что-то неправильно. Можете ли вы разместить конфигурацию Spring, включая источники данных и управление транзакциями? Каким классом является этот фрагмент Spring? Где ты нашел это? – nwinkler

+0

Этот код из класса JdbcTemplate. Он вызывается всякий раз, когда выполняется запрос, поэтому я сомневаюсь. –

+0

Пожалуйста, взгляните на мой обновленный ответ ... – nwinkler

ответ

9

Убедитесь, что DAO заворачивают в транзакции (например, используя перехватчики Spring для сделок) То же соединение затем будет использоваться для обоих вызовов

..

Еще лучше было бы иметь сделки один уровень выше, на уровне сервиса

Документация:. http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html

Update: Если вы посмотрите на JavaDoc из DataSourceUtils.getConnection() метода, который ссылается в своем обновлении, вы увидите, что она получает соединение, связанное с текущим потоком:

осознает соответствующее соединение, связанное с текущим потоком, например при использовании {@link DataSourceTransactionManager}. Будет связывать соединение с потоком , если транзакционная синхронизация активна, например. при работе в транзакции {@link org.springframework.transaction.jta.JtaTransactionManager JTA}).

В соответствии с этим, он должен работать так, как вы его настроили. Я использовал этот шаблон много раз, и никогда не бежал в каких-либо проблем, как вы описали ...

Обратите также внимание на этой теме, кто-то имел дело с подобными проблемами там: Spring Jdbc declarative transactions created but not doing anything

+0

У этого нет проблем с параллелизмом? Множественные вызовы службы будут по-прежнему использовать разные транзакции и, следовательно, разные соединения. Правильно? –

+0

Точно, это весь смысл использования демаркации транзакций на уровне обслуживания. Каждый вызов службы будет выполняться в своей собственной транзакции и будет использовать выделенное соединение с базой данных. После того, как транзакция будет выполнена или откат, соединение возвращается в пул и может использоваться в следующей транзакции. – nwinkler

+0

Большое спасибо. Сэкономил мне много документации :-) –

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; 
      } 
     });