Как использовать одно и то же соединение для двух запросов в Spring? - PullRequest
6 голосов
/ 21 марта 2012

У меня есть следующий код в дао на основе Spring JdbcTemplate -

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

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

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

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

Итак, у меня два вопроса:

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

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

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

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>

Ответы [ 2 ]

9 голосов
/ 21 марта 2012

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

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

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

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

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

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

Пожалуйста, посмотрите на эту ветку, там кто-то имел дело с похожими проблемами: Декларативные транзакции Spring Jdbc созданы, но ничего не делают

0 голосов
/ 07 ноября 2012

Это мой подход к этому:

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;
            }
        });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...