2013-11-26 2 views
0

데이터베이스 업데이트 중 하나가 실패 할 때 스프링 JDBC를 사용하는 스프링 트랜잭션 관리가 제대로 작동하는지 테스트하고 싶다.에러시 스프링 트랜잭션 관리가 작동하지 않는다

나는 콩을 구성하는 봄 선언적인 트랜잭션 관리를 사용
public void createWithContactInfo(String username, String name, Date dob, 
      String contactName, String contactPhone, String contactEmail) { 

     try { 
      String sqlStmt = "INSERT INTO person (username, name, dob) VALUES (?, ?, ?)"; 
      jdbcTemplateObject.update(sqlStmt, "paul", "Paul", dob); 

      sqlStmt = "INSERT INTO contact_info(username, customer_name, contact_name, contact_phone, contact_email) VALUES (?, ?, ?, ?, ?)"; 
      jdbcTemplateObject.update(sqlStmt, username, name, contactName, 
        contactPhone, contactEmail); 

     } catch (DataAccessException e) { 
      e.printStackTrace(); 
     } 
    } 

사람과 contact_info : 내 테스트 코드에서 다음

<tx:advice id="txAdvice" transaction-manager="transactionManager"> 
    <tx:attributes> 
     <tx:method name="createWithContactInfo"/> 
    </tx:attributes> 
</tx:advice> 

<aop:config> 
    <aop:pointcut id="createOperation" 
     expression="execution(* com.example.db.CustomerJDBCTemplate.createWithContactInfo(..))" /> 
    <aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation" /> 
</aop:config> 

<!-- Initialization for data source --> 
<bean id="dataSource" 
    class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 
    <property name="driverClassName" value="com.mysql.jdbc.Driver" /> 
    <property name="url" value="jdbc:mysql://localhost:3306/Customer" /> 
    <property name="username" value="myusername"/> 
    <property name="password" value="12345"/> 
    <property name="initialSize" value="10"/> 
</bean> 

<!-- Definition for customerJDBCTemplate bean --> 
<bean id="customerJDBCTemplate" class="com.example.db.CustomerJDBCTemplate"> 
    <property name="dataSource" ref="dataSource" /> 
</bean> 

<bean id="transactionManager" 
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
    <property name="dataSource" ref="dataSource" /> 
</bean> 

을, 내가 가진 : 다음 나의 두 DB 테이블을 갱신하는 코드입니다

public class JdbcTest { 
    public static void main(String[] args) { 
     ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); 
     CustomerDAO dao = (CustomerDAO) ctx.getBean("customerJDBCTemplate"); 
     Date dob = new Date(90, 9, 10); 
     dao.createWithContactInfo("m9087", "Sam", dob, "David", "123456", "[email protected]"); 
    } 
} 

주 프로그램을 실행 한 후에 나는 Duplicate entry 'm9087' for key 'PRIMARY'이라는 예외가 있습니다. 이는 m9087이 이미 contact_info 테이블에 존재하므로 예상됩니다. 하지만 트랜잭션에서 두 번째 DB 삽입이 실패한 이후로 나는 첫 번째 jdbcTemplateObject.update(sqlStmt, "paul", "Paul", dob);이 트랜잭션에서 커밋되지 않을 것이라고 생각했습니다. 그러나 나는 person 테이블을 확인하고이 username=paul 유효 항목을 반환

SELECT * FROM person WHERE username='paul'; 

이 첫 번째 DB 삽입 두 번째 DB 인서트 키 예외를 중복으로 인해 실패에도 불구하고 성공을 의미합니다.

DB 작업 중 하나라도 실패하면 트랜잭션이 롤백되어야하며 커밋되지 않습니다. 그러나이 경우 중복 키 예외로 인해 두 번째 DB 업데이트가 실패하더라도 첫 번째 DB 삽입이 계속 성공했습니다. 트랜잭션 관리의 잘못된 동작이 아닙니까? 내 설정이 트랜잭션 관리에서 올바 릅니까?

답변

3

예외를 잡기 때문에 롤백되지 않습니다. 검사되지 않은 예외가 발생하면 트랜잭션이 롤백됩니다. catch 블록을 사용하여 삼키고 있습니다.

catch (DataAccessException e) { 
    e.printStackTrace(); 
} 
+0

고마워. 이 문제가 해결되었고 첫 번째 DB 삽입이 실패 할 때 첫 번째 DB 삽입이 커밋되지 않습니다. 나는 실제로 Spring Transaction Example : http://www.tutorialspring.com/spring/declarative_management.htm을 따라 갔고 그 예제에서는 예외를 잡기 위해 try catch를 사용한다. 그러나이 예제에서는 'try' 블록에 예외가 발생하기 때문에 시나리오가 다릅니다. – tonga

2

JdbcTemplate은 두 트랜잭션 모두에서 두 업데이트 문을 모두 포함하는 트랜잭션을 자동으로 생성하지 않습니다.

@Autowire 
PlatformTransactionManager transactionManager; 

public void createWithContactInfo(String username, String name, Date dob, 
      String contactName, String contactPhone, String contactEmail) { 

    DefaultTransactionDefinition paramTransactionDefinition = 
             new DefaultTransactionDefinition(); 

    TransactionStatus status = 
      transactionManager.getTransaction(paramTransactionDefinition); 
    try{ 
     ... your 2 statmenets here ... 

     platformTransactionManager.commit(status); 
    }catch (Exception e) { 
     platformTransactionManager.rollback(status); 
    } 
} 
+0

감사합니다. Ralph. Spring 선언적 트랜잭션 관리를 사용하고 있습니다. 따라서 트랜잭션과 관련된 모든 것은 Bean 설정 XML 파일의 AOP에 의해 처리됩니다. 그러나 프로그래밍 방식의 트랜잭션 관리를 사용하면 솔루션이 제대로 작동합니다. – tonga