작성
·
1.5K
1
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)
[질문 내용]
Transaction을 어노테이션으로 설정하는 방법 중에 궁금한 점이 있습니다.
트랜잭션으로 선언하지 않은 메소드에서 트랜잭션로 선언한 내부 메서드를 불러오는 경우 AOP를 통하지 않기 때문에 @Transactional이 적용되지 않는다는 것은 이해하였습니다.
그리고 이 문제를 해결하기 위해 Class를 분리하여 주입해주는 방법으로 Proxy 클래스에서 메서드를 가져오는 것도 확인하였습니다.
확인을 위해 테스트를 작성하던 중 ReadOnly관련해서 질문이 생겼는데요.
트랜잭션을 ReadOnly를 True로 선언한 첫 번째 메서드에서 ReadOnly를 False로 선언한 두번째 메서드를 부룬뒤, 트랜잭션 매니저의 isCurrentTransactionReadOnly가 True에서 False로 변경되지 않을까 하였는데요.
생각과는 달리 변경되지 않는 것을 확인하였습니다.
이런 경우에는 첫번째 트랜잭션으로 이미 감싸져 있는 상태이기 때문에 두번째 트랜잭션이 무시된 것일까요?
그리고 TransactionSynchronizationManager.setCurrentTransactionReadOnly 메서드를 통해 ReadOnly의 속성을 변경할 수 있는 것을 확인하였는데, 실무에서 이렇게 TransactionSynchronizationManager를 통해 속성을 변경하여 사용하는 경우가 있을까요?
readOnly로 하여 많은 데이터를 가져온 후, 결과를 입력하는 경우에 데이터를 readonly로 가져오는 것이 빠르기도 하고 전체 프로세스를 같은 트랜잭션을 사용해 조금 유용하지 않을까 하여 질문드립니다.
답변 3
1
안녕하세요. 박세준님
readOnly 옵션의 경우 트랜잭션이 전파되는 중간에 변경이 불가능합니다. 새로운 트랜잭션을 시작하는 시점(커넥션을 획득하고 트랜잭션 시작하는 경우)에 최초 옵션만 적용됩니다.
쉽게 이야기해서 처음에 readOnly=true로 설정하면 해당 트랜잭션 내부에서 사용하는 readOnly 옵션들은 모두 무시됩니다.
감사합니다.
0
세부적으로 테스트를 진행하다가 좀 이상한게 있어서 공유드립니다.
이전 테스트로 @Transactional이 설정된 메소드에서 불러온 하위 @Transactional이 설정된 메소드의 리드온리 설정들은 먹히지 않는 것을 확인하였습니다.
이후에 테스트를 진행한 것은 @Transactional ReadOnly = false를 상위 메소드에서 일괄 적용한 비지니스 로직의 처리 속도와 @Transactional을 상위 메소드에는 적용하지 않은 체 세부적으로 select 메소드에는 ReadOnly로 , insert와 update에는 ReadOnly를 false로 설정한 메소드의 처리 시간을 비교해보았습니다.
일반적으로 생각했을때에는 세부적으로 설정한 것이 좀더 빠르지 않을까 생각하였는데요. 테스트를 해보니 오히려 전체적 메소드 처리에 @Transactional (ReadOnly = false)을 건 메소드가 약 40퍼센트 더 빨랐습니다.
전체적으로 트랜잭션을 건 메소드 평균 처리시간 : 약 2.5초
세부적으로 트랜잭션을 건 메소드 평균 처리시간 : 4초
평균 차이시간이 1.5초이상이니 굉장히 의미가 있는 결과라고 생각이 드네요.
@Transactional 어노테이션을 쉽게 붙이지만 반대로 내부에서는 리소스가 많이 소모되는 것일지도 모르겠네요.
이와 별개로 몇가지 테스트를 해보고 이 주제는 마무리 해야겠네요.
성능에 대한 부분은 DB와 DB 드라이버 마다 각각 다르게 나타날 수 있습니다. readOnly=true 옵션을 넣게되면 DB에 따라서 내부에서 최적화가 가능할 수 있지만, 또 한편으로 readOnly=true라는 것을 데이터베이스에 네트워크로 전송하는 경우가 발생할 수 있습니다.
그런데 트래픽이 정말 많지 않으면 암달의 법칙에 의해서 이 부분은 미미할 수 있습니다.
감사합니다.
0
현재 테스트한 내용을 공유합니다.
우선 리드온리가 설정이 메소드에서 변경이 가능 한 것인지, 서비스 별로 설정이 되는지 확인하였습니다.
테스트 방법은
1. ReadOnly가 적용되지 않은 서비스에서 리스트를 가져온다 .
2. ReadOnly가 적용된 서비스 or ReadOnly를 적용하여 리스트를 가져온다.
3. 두 리스트의 값들을 변경하여 더티체킹이 발생하는 지 확인한다.
입니다.
트랜잭션을 True에서 False로 변경을 시도하고 False에서 True로도 변경을 시도해보며 여러 테스트를 진행해보았습니다.
결론적으로는 메서드를 처음 불러올 때의 설정이 바뀌지는 않았습니다. 그러니까 이미 트랜잭션으로 감싼 뒤에는 TransactionSynchronizationManager.setCurrentTransactionReadOnly를 활용해보고 isCurrentTransactionReadOnly가 정상적으로 바뀌는 것은 확인하였지만, 처음 리드온리된 리스트의 경우에는 더티체킹이 발생하지 않았고, 반대의 경우에는 더티체킹이 발생하였습니다.
테스트 한 리파지토리도 공유드립니다.
https://github.com/parkjun5/TransactionAdvance/commit/4f14ecbfdff8c016b3108eea0583221ac45b8ce7
좀더 강의를 들어보며 트랜잭션에 대해 공부하고 다시 테스트를 해봐야겠네요.
세부적으로 트랜잭션을 나눠서 선언한 메소드에서 findAll 같은 셀렉 메소드는 아예 트랜잭션을 제거해봐도 전체 메소드에 트랜잭션을 넣는게 가장 빠르네요.
이러다가 보니 findAll과 같은 셀렉문에 트랜잭션이 필요한가? 라는 의문이 생겼네요.
해당 의문은 다행히 다른 분들도 해본 생각이여서 인터넷 자료를 보며 어차피 JPA를 활용하면 기본적으로 붙어버린 다는 것을 알게 되었습니다.
https://cupeanimus.tistory.com/90
http://www.blogjava.net/justinchen/archive/2009/04/15/265768.html
테스트한 깃 허브 주소입니다
https://github.com/parkjun5/TransactionAdvance/commit/ccbcf121f8a24100dce3d48b62ac855e99b75c35