@Transactional을 적용하여 어떠한 메소드를 실행한다면 롤백이 되었을 때 DB에 관련된 추가, 삭제등 로직은 @Transactional에 적용되어있는 AOP 로직에 의해 저절로 롤백이 됩니다. 하지만 레디스나 다른 스토리지에 어떠한 데이터를 추가하거나 삭제할 시 이를 수동으로 롤백시켜줘야 합니다. try-catch문을 이용하여 롤백되었을 때 로직을 처리해줄 수 있기는 합니다.
보통은 @Transactional 메소드 안에서 try catch문을 이용하여 RuntimeException이나 Error가 생겼을 시 롤백이 되면 catch문에서 잡는 방식으로 롤백이 되었을 때 로직을 수행하는데 이는 문제점이 있습니다.
롤백이 되었을 때 RuntimeException이나 Error가 생겨서 catch문 안에서 처리해주는 것과 정확히 "롤백이 되었을 때" 어떠한 처리를 해주는 것은 명확히 다른 상황입니다. 결과론적으로 기능은 동일하게 적용되지만 롤백이 되었을 때 어떠한 로직을 더 추가해주거나 할때 문제가 생길 수 있습니다.
또한 try-catch문을 사용시 try 문으로 모든 것을 감싸줘야 합니다.
또한 관심사의 문제도 해당합니다. catch문안에서 롤백이 되었을 때 로직을 수행해주는 것이랑 정확히 롤백이 생겼을 때 어떠한 로직을 수행해주는 것은 관심사의 범위가 다릅니다. catch문 안에서 어떠한 로직을 수행하는 것은 정확히 롤백이 생겼을 때 어떠한 로직을 수행해주겠다는 의미는 아니기 때문입니다.
결론적으로는 똑같은 기능으로 동작할 수 있으나 try catch문으로 이를 처리하면 정확히 롤백이 되었을 때 수행되는 로직이 아닙니다.
역시나 스프링에서는 Rollback hook을 제공해주고 있습니다. 스프링에서 제공해주는 TransactionSynchronization 클래스를 이용하면 트랜잭션이 커밋후, 트랜잭션 완료 후 등 여러가지 경우에서 트랜잭션 후에 로직들을 수행할 수 있습니다. 메소드로는 afterCommit, afterCompletion등이 있습니다.
제가 진행한 프로젝트에서 주문과 결제를 트랜잭션으로 한번에 처리하도록 하였습니다. DB에 있는 정보는 알아서 롤백이 되지만 레디스에서 장바구니를 삭제한 로직은 수동으로 다시 추가해주어야 합니다. 따라서 이러한 롤백 훅을 적용하였습니다.
롤백이 되었을 때 어떠한 로직을 실행하고 싶다면 다음과 같은 방식으로 사용하면 됩니다. ROLLBACK_STATUS 는 1이고 이는 스프링 공식문서에 상태별로 상수가 정해져있습니다. 0은 COMMIT된 STATUS입니다. 이는 스프링 공식문서에서 참고하면됩니다(맨밑에 첨부)
마지막으로 TransactionSynchronization 클래스를 쓸 때 주의해야할 점은 트랜잭션의 시작부분(@Transactional 메소드안의 시작부분)에 TransactionSynchronizationManager.registerSynchronization 메소드를 등록해야한다는 점입니다.
이는 TransactionSynchronizationManager.registerSynchronization 메소드 추가 전에 롤백이 된다면 롤백 후 로직을 수행하려는 저 메소드가 실행이 되지 않을 수도 있기 때문입니다.
프로젝트 url
https://github.com/f-lab-edu/make-delivery
참고자료
'make-delivery 프로젝트' 카테고리의 다른 글
[#6] Jenkins를 이용하여 CI/CD 환경 구축해보기 (2) | 2020.11.26 |
---|---|
[#5] 성능을 위해 Redis keys 대신 scan 이용하기 (0) | 2020.10.25 |
[#4] Spring에서 중복되는 로그인 체크 기능을 AOP로 분리하기 (0) | 2020.10.16 |
[#2] Redis에 한번에 많은 데이터 추가 시 네트워크 병목 개선하기 - Redis Pipeline 이용하기 (0) | 2020.10.08 |
[#1] 서버가 여러대면 로그인 정보는 어디에 저장할까? - Sticky Session, Session Clustering, Redis Session Storage (2) | 2020.09.02 |
댓글