2012-04-10 14 views
5

Sto provando a creare una soluzione basata su Spring per eseguire batch di query SQL sul server MySQL 5.5. Per "query" intendo qualsiasi istruzione SQL che compila, quindi il lavoro batch SQL può contenere per esempio più istruzioni CREATE TABLE, DELETE e quindi INSERT.Spring TransactionManager - commit non funziona

Sto usando Spring Batch per questo scopo.

Ho transactionManager configurato come segue.

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

e 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> 

La mia classe DAO ha il metodo configurato con

@Transactional(propagation = Propagation.REQUIRES_NEW) 

e passante ho più di un insieme di istruzioni SQL chiamando il metodo con istruzione SQL un tempo. L'elaborazione all'interno del metodo è il più semplice:

simpleJdbcTemplate.getJdbcOperations().execute(sql); 

Mi aspettavo che quando il metodo DAO completa, vorrei vedere i risultati nel DB. Tuttavia, sembra che solo quando l'esecuzione del lavoro Spring termina, i risultati diventano disponibili nel DB.

ho cercato di fare il commit all'interno del mio metodo 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"); 
} 

ho il debug del codice primavera e ho visto che l'impegno che io chiamo dal mio metodo DAO viene eseguito dal TransactionTemplate (il flusso raggiunge la linea this.transactionManager.commit(status); e passa senza eccezioni)

Apprezzerei qualsiasi consiglio su cosa dovrebbe essere fatto per rendere il metodo DAO da impegnare su ogni chiamata (commit dopo ogni istruzione SQL eseguita).

+0

@ L'annotazione di transazione si occupa dell'impegno. Nel tuo codice non è necessario fare riferimento al gestore delle transazioni e commettere esplicitamente la modifica, suppongo. – ch4nd4n

risposta

8

Non è possibile eseguire il proxy dei metodi privati. Il @Transactional che hai qui non ha alcun effetto. Tirare il metodo nell'interfaccia genitore e dovrebbe funzionare. A meno che tu non abbia l'impostazione proxyTargetClass abilitata che non è consigliata.

+0

ha modificato il metodo DAO in pubblico - lo stesso problema – aviad

+1

che ha richiamato il metodo nell'interfaccia padre ha aiutato la situazione. Shukran!:) – aviad

3

Quando si chiama il numero executeSingleQuery() dalla stessa classe, non si passa attraverso il proxy, quindi l'annotazione transazionale non avrà alcun effetto.

si stia mescolando le transazioni dichiarative e programmatiche, Presumibilmente si desidera REQUIRES_NEW così si potrebbe eliminare il senso @Transactional annotazione e utilizzare Propagation.REQUIRES_NEW prima di impostare il DefaultTransactionDefinition.

Inoltre, si potrebbe desiderare di spostare transactionManager.commit(status) all'interno del blocco try, il codice corrente rollback, poi tenta un commit quando si verifica un Exception.

+0

Grazie, ho votato la tua risposta perché è stata utile (in parte). Tuttavia non posso accettare 2 risposte e Madhe è stato il primo a rispondere ... – aviad

0

Abbiamo utilizzato l'annotazione @Rollback(value = false) e abbiamo risolto il problema riscontrato.

Problemi correlati