회사에서 @Transacational(readOnly = true) 일때 어떤 성능점 이점이 있을까? 라는 것을 생각해보았다.
기본적으로 무거운 Dirty Check 등을 안한다의 지식을 알고 있었는데, 근데 Dirty Check 는 왜 무거운데? 그리고 Snapshot 비교는? 등등 너무 궁금한 점이 많아져서 코드를 직접 분석하기로 했다.
일단 첫번째 코드는 isReadOnly 에 대한 분석인데, 설명을 간략하게 설명하면 아래와 같다.
이걸 read-only transaction 으로 optimize 할건지에 대한 여부를 알려주는 flag 라고 생각하면 된다.
참고로 어떻게 현재 트랜잭션에서 readOnly 여부를 알려주는 코드는 아래에 있다.
우리가 @Transactional(readOnly=true) 를 걸게 되면 일단 아래처럼 Hibernate 의 Session 의 FlushMode 가 MANUAL 이 된다.
예전글들을 보면, setFlushMode(FlushMode.MANUAL) 이렇게 되어 있는데, setFlushMode 는 직접 코드를 까봤더니 @Deprecated 된 메소드였다. 여하튼 Session 의 플러시모드가 메뉴얼이 됬다 정도만 이 코드에서 알면 된다. 아마도 txObject.isNewSession 과 관련된 메소드는 전파 옵션과 관련되있을거 같은데, 그건 나중에 다시한번보기로 하자.
아 그리고 한가지 중요한점이 있는데 저기 5.1 부터 생긴 setDefaultReadOnly 라는 메소드이다. 궁금해서 열어봤더니 entities 나 proxies 를 read-only mode 로 session 에서 설정한다는 뜻같다. 뭐 우리가 알고 있듯이, Read-Only 로 설정된 Entities 들은 수정될 수는 있으나 스냅샷을 비교하지 않는다. 즉 readOnly = true 상태의 SELECT 와 동일한 Transaction 내에서 Entity 를 변화시킨다고 자동으로 Dirty-Checking 이 일어나지 않는 이유이다. 위의 말이 이해가 안간다면 이글을 읽기보다는 JPA 를 다시 공부하는걸 추천한다.
이 위의 두 코드가 정말 중요하다.
일단 영속성 컨텍스트에 EntityEntry 가 추가되는 부분인데 우리는 위에서 말했듯이, entities and proxies 또한 read-only 모드이므로 READ_ONLY 로 저장된다. 그리고 더 중요한건 사실 EntityEntry 의 Status 에 저런 값들이 저장된 다는 것이다. 나는 주석만 보고 Entity 의 영속화 상태 이런건지 알았는데. READ_ONLY 와 같은 STATUS 를 관리한다는 것을 알았다.
이제 Dirty Check 를 하는 부분을 살펴보자. findDirty 라는 부분인데 우리가 볼 코드는 아래와 같다.
여기서 dirtyCheckPossible 를 결정하는 요소는 현재 Entry 의 loadedState 가 null 이 아닐 경우 가능한데 아래코드를 보면 READ_ONLY 일 경우 null 로 저장하게 된다. 따라서 우리는 persister.findDirty 라는 부분을 수행하지 않는 성능적 이점을 얻을 수 있다는 것을 일단 hibernate 코드를 통해 깨달았다.
후기
배민 면접볼때 권남님이 Transaction 에 관한질문을 주셨는데 그때 공부했던 기억이 났다.
이렇게 직접 코드를 분석해서 보니 훨씬 좋다.
그리고 생각보다.. 공식 라이브러리고 이렇다고 코드 규율이 엄한거 같지는 않다. 주석달아 놓은 거 보면 이런 것도 있었다. "이 이름이 적절하지 않은데, 일단 이런 역할을 하는 녀석이에요" 라는 것과. EntityMetaModel 클래스를 보면 생성자에 엄청 거대한 로직이 들어있다.
그렇다면 명시적이나 빠른 실패를 위해서라도 READ 하는 곳에서는 트랜잭션 readOnly=true 를 통해서 Dirty Checking 이 일어나는 걸 막는게 좋지 않을까? 라는 생각도 들었다.
'Spring' 카테고리의 다른 글
오늘자 삽질 - Spring Kafka (1) | 2022.04.13 |
---|---|
기존에 있던 Object 를 Bean 으로 등록하는 방법 (0) | 2022.04.05 |
Kotlin Spring 에서 Required = false 대신 ?(nullable) 을 사용가능한 이유 (0) | 2022.03.17 |
Hibernate 1 차 Cache 에 대해서 알아보자 (0) | 2022.03.10 |
MySQL 으로 형태소 분석기 없는 자동완성만들기 (0) | 2022.02.24 |