2012-04-10 21 views
5

Estoy intentando crear una solución basada en Spring para ejecutar un lote de consultas SQL en el servidor MySQL 5.5. Por "consulta" me refiero a cualquier instrucción SQL que compila, por lo que el trabajo por lotes SQL puede contener, por ejemplo, varias instrucciones CREATE TABLE, DELETE y luego INSERT.Spring TransactionManager - commit no funciona

Estoy usando Spring Batch para este fin.

Tengo transactionManager configurado de la siguiente manera.

<bean id="transactionManager" 
     class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
     <property name="dataSource" ref="dataSource" /> 
    </bean> 
    <tx:annotation-driven transaction-manager="transactionManager" /> 

y la dataSource:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 
    destroy-method="close"> 
    <property name="driverClassName" value="${batch.jdbc.driver}" /> 
    <property name="url" value="${batch.jdbc.url}" /> 
    <property name="username" value="${batch.jdbc.user}" /> 
    <property name="password" value="${batch.jdbc.password}" /> 
    <property name="maxIdle" value="10" /> 
    <property name="maxActive" value="100" /> 
    <property name="maxWait" value="10000" /> 
    <property name="validationQuery" value="select 1" /> 
    <property name="testOnBorrow" value="false" /> 
    <property name="testWhileIdle" value="true" /> 
    <property name="timeBetweenEvictionRunsMillis" value="1200000" /> 
    <property name="minEvictableIdleTimeMillis" value="1800000" /> 
    <property name="numTestsPerEvictionRun" value="5" /> 
    <property name="defaultAutoCommit" value="true" /> 
</bean> 

Mi clase DAO tiene el método configurado con

@Transactional(propagation = Propagation.REQUIRES_NEW) 

y el bucle I sobre una colección de las sentencias SQL llamando al método con las sentencias SQL un momento. El procesamiento en el interior del método es tan simple como:

simpleJdbcTemplate.getJdbcOperations().execute(sql); 

que esperaba que cuando el método DAO completa, me gustaría ver los resultados en la base de datos. Sin embargo, parece que solo cuando la ejecución del trabajo de Spring finaliza los resultados están disponibles en la base de datos.

Se ha intentado realizar la confirmación dentro de mi método DAO:

@Transactional(propagation = Propagation.REQUIRES_NEW) 
private void executeSingleQuery(String sql) { 
    PlatformTransactionManager transactionManager = (PlatformTransactionManager)context.getBean("transactionManager"); 


    DefaultTransactionDefinition def = new DefaultTransactionDefinition(); 
    def.setPropagationBehavior(Propagation.REQUIRED.ordinal()); 

    TransactionStatus status = transactionManager.getTransaction(def); 

    try { 
     // execute your business logic here 
     log.info("about to execute SQL query[" + sql + "]"); 
     simpleJdbcTemplate.getJdbcOperations().execute(sql); 

    } catch (Exception e) { 
     log.info("SQL query was not committed due to exception and was marked for rollback"); 
     transactionManager.rollback(status); 
    } 

    transactionManager.commit(status); 

    if (transactionManager.getTransaction(null).isRollbackOnly() 
      && transactionManager.getTransaction(null).isCompleted()) { 
     log.info("SQL query commited!"); 
    } else { 
     log.info("SQL query was not committed due to: 1) the transaction has been marked for rollback " + 
       "2) the transaction has not completed for some reason"); 
    } 

    log.info("the query has completed"); 
} 

I depurado el código de primavera y vi que la confirmación que llamo desde mi método DAO es ejecutado por TransactionTemplate (el flujo llegue a la línea this.transactionManager.commit(status); y pasa sin excepciones)

Agradecería cualquier consejo sobre lo que se debe hacer para hacer que el método DAO se confirme en cada llamada (confirmación después de cada instrucción SQL que ejecuta).

+0

@Transactional annotation se encarga de comprometerse. En su código, no necesita referencia al administrador de transacciones y supongo que debe realizar el cambio explícitamente. – ch4nd4n

Respuesta

8

No puede proxy métodos privados. es decir, el @Transactional que tiene aquí no tiene ningún efecto. Tire del método a su interfaz principal y debería funcionar. A menos que tenga habilitada la configuración proxyTargetClass, que no es recomendable.

+0

cambió el método DAO a público - el mismo problema – aviad

+1

al tirar el método a la interfaz principal ayudó a la situación. Shukran!:) – aviad

3

Cuando llama a su executeSingleQuery() desde dentro de la misma clase no va a través del proxy, por lo que la anotación transaccional no tendrá efecto.

Usted está mezclando las transacciones declarativas y programáticas, de suponer que quieren REQUIRES_NEW por lo que podría quitar el sentido @Transactional anotación y utilizar Propagation.REQUIRES_NEW al configurar su DefaultTransactionDefinition.

También, es posible que desee mover transactionManager.commit(status) dentro del bloque try, su código actual retrocede, luego intenta una confirmación cuando ocurre un Exception.

+0

Gracias, he votado positivamente su respuesta porque fue útil (parte de ella). Sin embargo, no puedo aceptar 2 respuestas, y MadheTo fue la primera en responder ... – aviad

0

Utilizamos la anotación @Rollback(value = false) y eso solucionó el problema al que se enfrenta.

Cuestiones relacionadas