현업에서 발생한 영속성 관리에 대한 질문입니다 ㅠㅠ
646
2 câu hỏi đã được viết
안녕하세요.
현업에서 JPA를 사용하게 되어 JPA 기본편을 듣고 JPA 활용을 듣고 있는 중입니다. 책도 사서 틈틈이 보고 있구요..
우선은 좋은 강의 정말 감사하다고 말씀드리고 싶구요. 이해에 정말 큰 도움이 되고 있습니다.
저는 지금 Spring Quartz 를 통해 배치를 돌면서 데이터를 생성/수정/삭제하는 어플리케이션 개발에 참여하게 되었습니다.
그 과정에서 아무리 삽질을 해도 이해가 안 되는 부분이 있어 질문드립니다..ㅠㅠ
질문은 크게 2가지 입니다.
1. Repository에 @Transactional 어노테이션이 없으면 "no entity manager 에러"
2. @Transactional 을 가진 Service와 @Transactional을 가진 Repository 를 오가며 쿼리하는 경우 "detached 에러"
첫번째는 크게 중요한 건 아닌데 두번째 질문과 연관되어 있는 내용인 거 같아서 질문 드립니다..
강사님은 Repository에 @Transactioanl 어노테이션을 안 붙이시는데,,
제가 현재 개발하고 있는 환경에서는 Repository에 @Transactioanl 어노테이션을 붙이지 않으면
"No EntityManager with actual transaction available for current thread" 에러가 발생합니다.
Spring Quartz 특성상 멀티 쓰레드로 동작하기 때문에 그런 거 같은데 모르겠네요 ㅠㅠ
참고로 repository는 @Autowire 가 아니라 아래처럼 직접 applicationContext에서 꺼내서 사용하고 있습니다.

두번째가 저에게 현재 큰 어려움을 주고 있는 부분인데요 ㅠ
영속성 관리에 대한 질문입니다..


이런 Id를 멀티 키로 2개 사용하는 엔티티가 있다고 할 때,

이렇게 레포지토리에서 2개의 메소드를 만듭니다.
1. ID 중 하나를 조건으로 목록을 조회하는 메소드
2. 목록을 주면 순회하며 삭제하는 메소드

이제 서비스에서 해당 목록 조회 메소드 호출 후 삭제 메소드를 호출했을 때,
저의 예상은 이렇습니다.
1. 목록 조회 시 영속성 컨텍스트에 객체 목록이 올라감 > select 쿼리 1번 호출
2. 컨텍스트에 있는 객체 목록을 삭제함 > delete 쿼리 N번 호출
하지만 실제 동작은 이렇습니다.
1. 목록 조회 -> select 쿼리 1회 호출
2. 목록 삭제 -> 객체 삭제 -> select 쿼리 1회 호출 후 "Removing a detached instance" 에러 발생
"Removing a detached instance ~~.SomeEntity#SomeEntityId nested exception is java.lang.IllegalArgumentException"
왜 그러는 걸까요..??? ㅠㅠㅠ
remove 를 요청했는데 select 쿼리가 날라가는 이유는 또 뭘까요..???
1. 목록 조회 메소드에서 삭제까지 바로 이어서 진행하면 또 예상대로 삭제가 잘 진행됩니다..
2. 삭제 메소드에서 다시 한 번 조회 쿼리를 호출한 후 삭제해도 삭제가 됩니다..
즉, 레포지토리에서 조회->삭제하면 정상 삭제가 되는데,
서비스 -> 레포지토리:조회 -> 서비스 -> 레포지토리:삭제 처럼 서비스와 레포지토리를 거쳐가면 detached 에러가 발생하는 상황입니다..
영속성 컨텍스트가 서비스 클래스까지 유지가 안 되는 걸까요?
유지시키려면 어떻게 해야할까요..???
영속성 컨텍스트가 내부적으로 어떻게 동작하고 있는 건지 알 수가 없네요 ㅠㅠ
질문이 조금 길어졌지만.. 답변해주시면 정말 감사할 거 같습니다..ㅠㅠ 부탁드립니다..!
Câu trả lời 3
1
안녕하세요. 이영규님
영속성 컨텍스트는 스프링의 트랜잭션 범위와 같다고 생각하시면 됩니다.
그런데 지금 SampleTask가 제 생각에는 @Transactional이 붙어있지만 트랜잭션이 정상 동작하지 않은 것 같아요.
이 부분에 대한 점검이 먼저 필요합니다.
그런데 우선은 다음과 같이 한번 진행해보세요.
XxxService를 만들고 여기에 트랜잭션을 붙인 다음 다음과 같이 이 서비스를 꺼내서 한번 사용해보세요.
XxxService xxxService = getBean(XxxService);
SampleTask는 단순히 이 서비스의 로직을 호출하기만 하는 것으로 변경해주세요.
xxxService.execute(..)처럼요
그리고 모든 로직은 이 서비스 안에 있어야 합니다. 이 서비스 밖에 나오는 순간 트랜잭션이 종료되면서 영속성 컨텍스트도 날라가버립니다.
감사합니다.
0
ㅎㅎ 네 잘 찾으셨네요. new Service를 하게되면 스프링이 관리하지 않기 때문에 트랜잭션 관리가 안되겠지요.
(팀 분들은 집에서도, 회사에서도 제 목소리가 들린다고 합니다 ㅋㅋ)
0
감사합니다..!
말씀해주신대로 테스트해봤더니 잘 되더라구요.
원인은 아직 정확히는 이해하지 못 했지만,,
결론은 이렇습니다.
new Service() 로 Service 생성 -> 서비스 내부에서 getBean으로 Repository 생성 : Service와 Repository 간의 Transactional 유지 안 됨
getBean으로 Service 생성 -> 서비스 내부에서 @Autowire 로 Repository 생성 : Service와 Repository 간의 Transactional 유지 됨
애초에 Service를 new Service()로 생성한 거부터 문제였던 거 같아요.
덕분에 문제 잘 해결했습니다. 정말 감사합니다.
요즘에 여자친구 목소리보다 선생님 목소리를 더 많이 듣고 있는 거 같습니다..ㅎㅎ
앞으로도 열심히 수강하겠습니다. 감사합니다.
테스트 질문, 어떤것을 사용할것인것에 대해서
0
87
1
setter 사용하지 않기
0
94
1
안녕하세요 치킨 디도스 이벤트 보고 흉내내보려 들어왔습니다..
0
124
2
OrderServiceTest 상문주문 테스트 시 update 쿼리 문의
0
103
1
sdk 설정 오류
0
186
2
오탈자 - @Transactional
0
122
1
src/test/resources 테스트 경로 문제
0
138
1
상품 등록후 H2 db 출력 순서 바꿀 수 있나요?
0
119
1
MemberRepositoryTest 실행오류
0
172
1
boot 4.x >>> trasasction rolled back log & p6spy(영한님, 수업 자료 업데이트 해주시면 감사하겠습니다!!)
1
291
2
강의 마지막 QueryDSL 사용 부분 질문있습니다
2
227
2
클라이언트에서 isbn과 author 수정 요청을 한 경우에 대해 질문드립니다.
0
104
1
도메인 모델 패턴 vs 트랜잭션 스크립트 패턴
0
161
1
기본 생성자
0
117
1
h2 DB 연결시 jdbc url 변경 이유가 궁금합니다.
0
169
1
멤버서비스테스트 부분에서 막힙니다.
0
277
4
실무에서도 EntityManager를 이용해서 많이 작업하는 편일까요?
0
213
1
초반에 h2 다운로드 과정 꼭 필요한가요?
0
203
2
자신 필드에도 get으로 접근하는 이유가 있을까요?
0
205
1
24분 27초 연관관계 편의 메서드 위치
0
169
1
단건 주문만 가능하게 한건 의도한 부분이신가요?
0
162
2
빌드 툴, Gradle
0
129
1
h2연결은 된 것 같은데 엔티티 테이블까지 작성 후 확인해보아도 테이블이 안보입니다
0
127
2
Repository에서 EntityManager 주입 방식 차이
0
155
1

