2012-04-10 12 views
5

Próbuję stworzyć oparte na źródle rozwiązanie do uruchamiania partii zapytań SQL na serwerze MySQL 5.5. Przez "zapytanie" rozumiem każdą instrukcję SQL, która się kompiluje, więc zadanie wsadowe SQL może zawierać na przykład kilka instrukcji CREATE TABLE, DELETE, a następnie INSERT.Spring TransactionManager - commit nie działa

Używam do tego celu Spring Batch.

Mam transactionManager skonfigurowany w następujący sposób.

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

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

Moja klasa DAO ma metodę skonfigurowany z

@Transactional(propagation = Propagation.REQUIRES_NEW) 

i I pętli nad zbiór instrukcji SQL wywołanie metody z jednej instrukcji SQL czas. Przetwarzanie wewnątrz tej metody jest bardzo proste:

simpleJdbcTemplate.getJdbcOperations().execute(sql); 

, że oczekuje się, że po zakończeniu sposób DAO ja patrz wyniki w PB. Jednak wydaje się, że tylko wtedy, gdy wykonanie zadania Spring zakończy się, wyniki stają się dostępne w DB.

Próbowałem zrobić to popełnić wewnątrz mojej metody 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 debugowania kodu wiosną i zobaczył, że zobowiązują się nazywam od mojej metody DAO jest wykonywany przez TransactionTemplate (przepływ osiąga linię this.transactionManager.commit(status); i przechodzi bez wyjątków)

Byłbym wdzięczny za wszelkie porady, co należy zrobić, aby metoda DAO była zatwierdzana przy każdym wywołaniu (zatwierdzenie po każdym poleceniu SQL, które wykonuje).

+0

@ Adnotacja transakcyjna zajmuje się zatwierdzaniem. W twoim kodzie nie ma potrzeby odwoływania się do menedżera transakcji i zatwierdzania zmiany jawnie, jak przypuszczam. – ch4nd4n

Odpowiedz

8

Nie można pośredniczyć w prywatnych metodach proxy. To znaczy, że @Transactional, który tu masz, nie ma żadnego efektu. Przeciągnij metodę do interfejsu nadrzędnego i powinna działać. O ile nie jest włączone ustawienie proxyTargetClass, które nie jest zalecane.

+0

zmieniono metodę DAO na publiczną - ten sam problem powodował – aviad

+1

podciągnięcie metody do interfejsu nadrzędnego. Shukran!:) – aviad

3

Jeśli zadzwonisz pod numer executeSingleQuery() z tej samej klasy, nie przejdziesz przez serwer proxy, więc adnotacja transakcyjna nie przyniesie efektu.

Jesteś mieszanie transakcji deklaratywnych i programowe, przypuszczalnie chcesz REQUIRES_NEW więc można usunąć bezsensowną @Transactional adnotacji i używać Propagation.REQUIRES_NEW podczas konfigurowania DefaultTransactionDefinition.

Również może chcesz przenieść transactionManager.commit(status) wewnątrz bloku try, aktualna kod wycofuje, a następnie próbuje commit gdy wystąpi Exception.

+0

Dzięki, podniosłem twoją odpowiedź, ponieważ była pomocna (część). Jednak nie mogę zaakceptować 2 odpowiedzi - a MadheTo jako pierwsza odpowiedziała ... – aviad

0

Użyliśmy adnotacji @Rollback(value = false), która rozwiązała problem, przed którym stoisz.

Powiązane problemy