2012-04-10 2 views
5

MySQL 5.5 서버에서 SQL 쿼리를 실행하기위한 스프링 기반 솔루션을 만들려고합니다. "query"는 컴파일하는 모든 SQL 문을 의미하므로 SQL 배치 작업에는 여러 CREATE TABLE, DELETE 및 INSERT 문이 포함될 수 있습니다.Spring TransactionManager - 커밋이 작동하지 않습니다.

나는이 목적으로 Spring Batch을 사용하고 있습니다.

나는 transactionManager을 다음과 같이 구성했습니다.

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

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> 

내 DAO 클래스는 하나의 SQL 문을 사용하여 메소드를 호출하는 SQL 문 모음을 통해

@Transactional(propagation = Propagation.REQUIRES_NEW) 

내가 루프로 구성하는 방법이있다 시간.

simpleJdbcTemplate.getJdbcOperations().execute(sql); 

내가 DAO 방법이 완료되면, I는 DB에 결과를 볼 것으로 예상 : 있어서 내부 처리만큼 간단하다. 그러나 스프링 작업 실행이 완료된 경우에만 결과가 DB에서 사용 가능 해지는 것처럼 보입니다.

내가 내 DAO 방법 내부 커밋하려고 노력 : 나는 봄의 코드를 디버깅하고, 내가 (흐름 선에 도달 TransactionTemplate의에 의해 실행되는 내 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"); 
} 

this.transactionManager.commit(status); 및 아무 예외없이 전달)

DAO 메소드가 모든 호출 (커밋 된 모든 SQL 문 실행 후 커밋)을 커밋하도록하려면 어떻게해야하는지 조언 해 주시면 감사하겠습니다.

+0

@Transactional 주석은 커밋을 처리합니다. 귀하의 코드에서 트랜잭션 관리자에 대한 참조가 필요하지 않고 명시 적으로 변경을 적용한다고 가정합니다. – ch4nd4n

답변

8

개인 메서드를 프록시 처리 할 수 ​​없습니다. 즉 당신이 여기에있는 @ 트랜잭션은 효과가 없습니다. 부모 인터페이스로 메소드를 가져 오면 제대로 작동합니다. proxyTargetClass 설정을 사용하도록 설정하지 않은 경우에는 권장되지 않습니다.

+0

DAO 방법을 공개로 변경 - 동일한 인터페이스 – aviad

+1

을 부모 인터페이스로 가져 와서 상황을 도왔습니다. 슈크란!:) – aviad

3

동일한 클래스에서 executeSingleQuery()으로 전화를 걸면 프록시를 통해 연결되지 않으므로 트랜잭션 주석이 적용되지 않습니다. 당신은 선언적 및 프로그래밍 거래를 혼합하는

는, 아마도 당신은 DefaultTransactionDefinition 당신을 설정할 때 REQUIRES_NEW 그래서 당신은 무의미 @Transactional 주석을 제거하고 Propagation.REQUIRES_NEW를 사용할 수 있습니다합니다.

또한 try 블록 안에 transactionManager.commit(status) 블록을 이동하려는 경우 현재 코드가 롤백 된 다음 Exception이 발생하면 커밋을 시도합니다.

+0

감사합니다, 나는 그것이 도움이 되었기 때문에 당신의 대답을 upvote (일부). 그러나 나는 2 개의 대답을 받아 들일 수 없다. 그리고 MadheTo는 1 등이었다. – aviad

0

@Rollback(value = false) 주석을 사용하고 직면 한 문제가 해결되었습니다.

관련 문제