스프링 DB 2편(데이터 접근 활용 기술)

Ch10. 스프링 트랜잭션 전파(기본) - 트랜잭션 두 번 사용

webmaster 2022. 7. 7. 15:08
728x90

double_commit()

@Test
public void double_commit(){
    log.info("트랜잭션1 시작");
    TransactionStatus tx1 = txManager.getTransaction(new DefaultTransactionAttribute());
    log.info("트랜잭션1 커밋");
    txManager.commit(tx1);

    log.info("트랜잭션2 시작");
    TransactionStatus tx2 = txManager.getTransaction(new DefaultTransactionAttribute());
    log.info("트랜잭션2 커밋");
    txManager.commit(tx2);
}
  • 트랜잭션 1
    • Acquired Connection [HikariProxyConnection@2028630031 wrapping conn0: url=jdbc:h2:mem:aea82df1-3d76-4e58-871a-cb3c8e66b2cf user=SA] for JDBC transaction
      • 트랜잭션 1을 시작하고, 커넥션 풀에서 conn0 커넥션을 획득했다.
    • Releasing JDBC Connection [HikariProxyConnection@2028630031 wrapping conn0: url=jdbc:h2:mem:aea82df1-3d76-4e58-871a-cb3c8e66b2cf user=SA] after transaction
      • 트랜잭션 1을 커밋하고, 커넥션 풀에 conn0 커넥션을 반납했다.
  • 트랜잭션 2
    • Acquired Connection [HikariProxyConnection@607504046 wrapping conn0: url=jdbc:h2:mem:aea82df1-3d76-4e58-871a-cb3c8e66b2cf user=SA] for JDBC transaction
      • 트랜잭션 2를 시작하고, 커넥션 풀에서 conn0 커넥션을 획득했다.
    • Releasing JDBC Connection [HikariProxyConnection@607504046 wrapping conn0: url=jdbc:h2:mem:aea82df1-3d76-4e58-871a-cb3c8e66b2cf user=SA] after transaction
      • 트랜잭션 2를 커밋하고, 커넥션 풀에 conn0 커넥션을 반납했다.

주의! 로그를 보면 트랜잭션 1과 트랜잭션 2가 같은 conn0 커넥션을 사용 중이다. 이것은 중간에 커넥션 풀 때문에 그런 것이다. 트랜잭션 1은 conn0 커넥션을 모두 사용하고 커넥션 풀에 반납까지 완료했다. 이후에 이후에 트랜잭션 2가 conn0를 커넥션 풀에서 획득한 것이다. 따라서 둘은 완전히 다른 커넥션으로 인지하는 것이 맞다. 그렇다면 둘을 구분할 수 있는 다른 방법은 없을까? 히카리 커넥션 풀에서 커넥션을 획득하면 실제 커넥션을 그대로 반환하는 것이 아니라 내부 관리를 위해 히카리 프록시 커넥션이라는 객체를 생성해서 반환한다. 물론 내부에는 실제 커넥션이 포함되어 있다. 이 객체의 주소를 확인하면 커넥션 풀에서 획득한 커넥션을 구분할 수 있다.

히카리 커넥션풀이 반환해주는 커넥션을 다루는 프록시 객체의 주소가 트랜잭션 1은 HikariProxyConnection@1000000 이고, 트랜잭션 2는 HikariProxyConnection@2000000 으로 서로 다른 것을 확인할 수 있다.

결과적으로 conn0 을 통해 커넥션이 재사용된 것을 확인할 수 있고, HikariProxyConnection@1000000 , HikariProxyConnection@2000000 을 통해 각각 커넥션 풀에서 커넥션을 조회한 것을 확인할 수 있다.

서로 다른 커낵션을 얻어 트랜잭션을 동작시킨다.

  • 트랜잭션이 각각 수행되면서 사용되는 DB 커넥션도 각각 다르다.
  • 이 경우 트랜잭션을 각자 관리하기 때문에 전체 트랜잭션을 묶을 수 없다. 예를 들어서 트랜잭션1이 커밋하고, 트랜잭션 2가 롤백하는 경우 트랜잭션 1에서 저장한 데이터는 커밋되고, 트랜잭션 2에서 저장한 데이터는 롤백된다. 

double_commit_rollback()

@Test
public void double_commit_rollback(){
    log.info("트랜잭션1 시작");
    TransactionStatus tx1 = txManager.getTransaction(new DefaultTransactionAttribute());
    log.info("트랜잭션1 커밋");
    txManager.commit(tx1);

    log.info("트랜잭션2 시작");
    TransactionStatus tx2 = txManager.getTransaction(new DefaultTransactionAttribute());
    log.info("트랜잭션2 롤백");
    txManager.rollback(tx2);
}
  • 로그를 보면 트랜잭션1은 커밋되지만 트랜잭션 2는 롤백된다.

 

728x90