2012-04-10 10 views
5

Ich versuche, Spring-basierte Lösung für die Ausführung Batch von SQL-Abfragen auf MySQL 5.5-Server zu erstellen. Mit "Abfrage" meine ich jede SQL-Anweisung, die kompiliert, so dass der SQL-Batch-Job zum Beispiel mehrere CREATE TABLE, DELETE und dann INSERT-Anweisungen enthalten kann.Spring TransactionManager - Commit funktioniert nicht

Ich verwende Spring Batch für diesen Zweck.

Ich habe transactionManager wie folgt konfiguriert.

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

und die 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> 

Meine DAO Klasse hat die Methode konfiguriert mit

@Transactional(propagation = Propagation.REQUIRES_NEW) 

und ich Schleife über eine Sammlung von SQL-Anweisungen, die Methode mit einzelnen SQL-Anweisung aufrufen eine Zeit. Die Verarbeitung innerhalb der Methode ist so einfach wie:

simpleJdbcTemplate.getJdbcOperations().execute(sql); 

Ich erwartete, dass, wenn die DAO-Methode abgeschlossen ist, ich die Ergebnisse in der DB sehen würde. Es sieht jedoch so aus, als ob die Ausführung des Spring-Jobs erst dann abgeschlossen wird, wenn die Ergebnisse in der Datenbank verfügbar sind.

Ich habe versucht, das Commit in meinem DAO-Methode zu tun:

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

ich den Frühling Code debuggt und sah, dass die befehle ich Anruf von meinem DAO-Methode von TransactionTemplate ausgeführt wird (der Fluss erreicht die Linie this.transactionManager.commit(status); und besteht ausnahmslos)

Ich würde mich über jeden Hinweis freuen, was getan werden sollte, damit die DAO-Methode bei jedem Aufruf festgeschrieben wird (Commit nach jeder ausgeführten SQL-Anweisung).

+0

@Transaktionale Annotation kümmert sich um das Commit. In Ihrem Code brauchen Sie keinen Verweis auf den Transaktionsmanager und die Änderung wird explizit übernommen, nehme ich an. – ch4nd4n

Antwort

8

Sie können keine privaten Methoden verwenden. Die @Transactional, die Sie hier haben, hat keine Wirkung. Ziehen Sie die Methode zu Ihrer übergeordneten Schnittstelle und es sollte funktionieren. Es sei denn, Sie haben die Einstellung proxyTargetClass aktiviert, die nicht empfohlen wird.

+0

hat die DAO-Methode auf "public" geändert - dasselbe Problem – aviad

+1

Die Methode zur übergeordneten Schnittstelle hochzuziehen half der Situation. Shukran!:) – aviad

3

Wenn Sie Ihre executeSingleQuery() aus derselben Klasse anrufen, gehen Sie nicht über den Proxy, so dass die Transaktionsannotation keine Auswirkungen hat.

Sie deklarative und programmatische Transaktionen Mischen Vermutlich wollen Sie REQUIRES_NEW so könnte man die sinnlose @Transactional Anmerkung entfernen und Propagation.REQUIRES_NEW verwenden, wenn Ihre DefaultTransactionDefinition einrichten.

Auch möchten Sie vielleicht transactionManager.commit(status) innerhalb der try Block verschieben, Ihr aktueller Code rollt zurück, dann versucht eine Festschreibung, wenn eine Exception auftritt.

+0

Danke, ich habe deine Antwort verbessert, weil sie hilfreich war (Teil davon). Allerdings kann ich keine zwei Antworten akzeptieren - und MadheTo war der erste, der antwortete ... – aviad

0

Wir haben die @Rollback(value = false) Annotation verwendet und damit das Problem behoben.