2012-03-21 17 views
6

Tengo el siguiente código en un DAO basado primavera JdbcTemplate -¿Cómo usar la misma conexión para dos consultas en Spring?

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

El problema es que a veces mi mi actualización y consultas queryForInt se ejecutan utilizando diferentes conexiones de la agrupación de conexiones.

Esto da como resultado el regreso de un recordId incorrecto ya que se supone que MySql last_insert_id() se llama desde la misma conexión que emitió la consulta de inserción.

He considerado el SingleConnectionDataSource pero no quiero usarlo ya que degrada el rendimiento de la aplicación. Solo quiero una conexión única para estas dos consultas. No para todas las solicitudes de todos los servicios.

así que tengo dos preguntas:

  1. Se puede gestionar la conexión utilizada por la clase de plantilla?
  2. ¿JdbcTemplate realiza la gestión automática de transacciones? Si manualmente aplico una transacción a mi método Dao, ¿eso significa que se crearán dos transacciones por consulta?

Esperando que ustedes puedan arrojar algo de luz sobre el tema.

Actualización - Probé el enfoque de nwinkler y envolví mi capa de servicio en una transacción. Me sorprendió ver que el mismo error aparecía de nuevo después de algún tiempo. Excavar en el código fuente de la primavera me encontré con esto -

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

Así que al contrario de lo que pensaba, no hay necesariamente una conexión a la base por transacción, pero una conexión para cada consulta ejecutada. Lo que me devuelve a mi problema. Quiero ejecutar dos consultas desde la misma conexión. :-(

actualización -

<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, entonces supongo que todavía estás haciendo algo mal. ¿Puedes publicar tus configuraciones Spring, incluida la fuente de datos y la gestión de transacciones? ¿De qué clase es ese fragmento de Spring? ¿Dónde encontraste esto? – nwinkler

+0

Ese código es de la clase JdbcTemplate. Se llama siempre que se ejecuta una consulta, de ahí mi duda. –

+0

Por favor, eche un vistazo a mi respuesta actualizada ... – nwinkler

Respuesta

9

Asegúrese de que su DAO está envuelto en una transacción (por ejemplo, mediante el uso de interceptores de resorte por Transacciones) La misma conexión se utilizará tanto para llamadas

..

Aún mejor sería tener las transacciones de un nivel superior, en la capa de servicio

Documentación:. http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html

Actualización: Si se echa un vistazo en el JavaDoc del método DataSourceUtils.getConnection() la que hizo referencia en su actualización, se verá que se obtiene la conexión asociada con el flujo actual:

Es consciente de una conexión correspondiente vinculada a la secuencia actual, por ejemplo al usar {@link DataSourceTransactionManager}. Se vinculará una conexión al hilo si la sincronización de la transacción está activa, p. cuando se ejecuta dentro de una transacción {@link org.springframework.transaction.jta.JtaTransactionManager JTA} ).

De acuerdo con esto, debería funcionar como si lo hubiera configurado. He utilizado este patrón muchas veces, y nunca se encontró con ningún problema como se describen ...

Por favor, también echa un vistazo a este hilo, alguien estaba tratando con problemas similares allí: Spring Jdbc declarative transactions created but not doing anything

+0

Esto no tiene ningún problema de concurrencia, ¿verdad? Las múltiples invocaciones del servicio seguirán usando diferentes transacciones y, por lo tanto, conexiones diferentes. ¿Derecha? –

+0

Exactamente, ese es el objetivo de usar la demarcación de transacciones en la capa de servicio. Cada llamada de servicio se ejecutará en su propia transacción y utilizará una conexión de base de datos dedicada. Una vez que la transacción se confirma o revierte, la conexión se devuelve al grupo y se puede usar en la próxima transacción. – nwinkler

+0

Muchas gracias. Me salvó revisando mucha documentación :-) –

0

Este es mi enfoque para hacer esto:

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