나다.
이 글이 뭐하는 글이냐면
우리는 살면서 어이없는 일들과 마주하게 된다.
그리고 대부분의 어이없는 일들은 사소한 실수에서 비롯된다.
이 글의 제목 또한 굉장히 사소한 실수에서 발생하는 개 같은 일인데
이번 글을 통해 같은 실수를 하는 사람이 적어지길 바라는 마음으로 쓴다.
왜 이 오류가 발생했냐면
우리는 어떤 코드를 완성하면 테스트를 한다.
이는 척수반사와 같은 현상인데 테스트는 무조건적으로 시행되어야만
코드에 존재하는 하자를 검증할 수 있기 때문이다.
물론 비단 테스트를 할 때뿐 아니라 어느 경우든 발생할 수 있지만
내 생각에 대부분 테스트 단계에서 어떤 것을 저장할 때 발생하게 될 텐데
이 오류는 EntityManager가 persist() 함수를 호출 받았으나
함수를 처리 할 Transaction 단위가 존재하지 않을 때 출력되는 오류다.
맞음. @Transactional 안 붙혀서 출력되는 오류임.
다음의 테스트는 정상작동하지 않는다.
하지만 위의 테스트에 @Transactional을 붙여준다면
잘 된다.
JPA는 Transaction 단위로 기능을 수행한다.Transaction 단위로 구성된 작업에 따라 1차 캐시에 저장한 entity 들이 데이터베이스에 flush되어 영속화되는 구조인데 Transaction 자체가 없으니동작할 리가 없지 않은가?
편하게 사용하고 싶다면
@Transactional을 모든 메소드마다 붙히고 다닌다면 개같이 귀찮아질 것이다.
그렇기 때문에 이 Transactional 어노테이션은 클래스 단위로도 붙일 수 있는데
기본적으로 @Transactional의 속성 중 readonly의 경우 default가 false로 설정되어 있다.
맞음. true면 읽기 전용임 ㅇㅇ.
그렇기 때문에 경우에 따라 사용법을 좀 바꾸면 편하게 쓸 수 있는데
해당 클래스가 수행해야 할 항목 중 조회의 성격이 많은 경우
@Service
@RequiredArgsConstructor
@Transactional(readonly = true)
class 어쩌고저쩌고Service {
private final 어쩌고Repository 저쩌고Repository
void 읽는거(Long 읽어야 할거 아이디) {
블라블라;
}
@Transactional
void 쓰는거(저장해야 될 객체) {
블라블라;
}
}
클래스에 통째로 readonly를 씌워놓은 후 읽기가 아닌 쓰기 등과 같은 동작을 해야 할 메소드에만
따로 @Transactional 을 붙여 사용하면 된다.
클래스보다 메소드에 붙어있는게 우선으로 적용됨.
@Service
@RequiredArgsConstructor
@Transactional
class 어쩌고저쩌고Service {
private final 어쩌고Repository 저쩌고Repository;
@Transactional(readonly = true)
void 읽는거(Long 읽어야 할거 아이디) {
블라블라;
}
void 쓰는거(저장해야 될 객체) {
블라블라;
}
}
반대로 쓰면 이렇게 되겠쥬?
그러니 저 오류를 본다면 민첩하게 @Transactional을 붙이도록 하자.
그럼 다들 민첩한 하루 되시길 :)
'JPA' 카테고리의 다른 글
[JPA] 연관관계 맵핑(다대일 / N:1) (2) | 2022.12.28 |
---|---|
[JPA] JPA와 PK 그리고 Id (1) | 2022.12.28 |
[JPA] 영속성 컨텍스트와 Flush (4) | 2022.12.22 |
[JPA] 영속성 컨텍스트란 무엇인가. (0) | 2022.12.22 |
[JPA] JPA란 무엇인가. (1) | 2022.12.20 |