티스토리 뷰
SpringBoot + MariaDB 5-4 프로필페이지 open in view개념(Lazy, EAGER ) @Transactional을 걸어줘야하는 이유(select문에도)
svdjcuwg4638 2023. 6. 12. 20:59오류 원인
전글에서의 오류 원인은 ImageService에 사진업로드 함수안에 System.out.println(imageEntity);가 문제였다 왜 그런걸까?
위부분을 주석하고 저장한뒤 사진 업로드하면 정상적으로 업로드가된다.
무한참조
1. imageEntity가 sysout실행
2. domain.image.image.java에 있는 모든 getter가 실행
3. image에 있는 User getter가 발생
4. image 안에 있는 List<Image> 안에 Image도 실행된다
다시 1,2 ,3 ,4 형태로 무한참조를 반복하게된다.
우리가 보통 sysout로 객채를 출력하게되면 알아서 .toString이 붙게된다.
toString을 안만들었는데 어떻게 있냐면 @Data에서 알아서 만들어줘서 몰랐던것이다.
toString을 생성하면 생긴건 이러하다.
위 코드에서 return값에서 첫줄 맨뒤 user부분만 삭제를 해보자
그럼다시 syso에 imageEntity를 출력하게하고 다시 업로드를 해보자
확인해보면 잘 되는것을 확인할 수 있다.
여기서 느낄 수 있는점은 sysout과 무한참조를 조심해야한다
필요없는 변수저장과 출력은 최대한 지워주는게 좋습니다.
요청이 진행되는 과정
1. 클라이언트가 보낸 요청을 디스패쳐가 받음
2. DB에 접근할 수 있는 세션이 생성되어 controller에 감
3. controller은 repository로 전해짐
4. repository에서 영속성 컨텍스트에게 요청을보내고 데이터가 있으면 바로 반환이 될것이고
없다면 DB에 요청을하고 영속성 컨텍스트에 저장이되고 repository에 돌아올것이다.
5.repository - service로 전해지고 service가 끝나는 시점에서 세션이 종료된다.
6. controller에서 세션이 사라졌으니 lazy로딩이 불가능하다
lazy로딩이란?
우리가 User클래스에서 images를 요청할때 fetch = FetchType.LAZY라고 지정하였다
이때 LAZY는 밑의 과정에서 db까지 가서 user를 영속성 컨텍스트에 저장하고 그뒤에 컨트롤로 돌아와서 db에 다시 image를 요청하게 되는데 세션이 그전에 끝난다면 db에 데이터를 요청 할 수가 없다 왜? 세션이 끝났으니까
EAGER 을 사용한다면 어떠할까 사용가능하다 왜냐하면 EAGER은 DB에서 바로 같이 join요청을하여 영속성 컨텍스트에 user와 images가 같이 저장되기 때문이다.
open-in-view:false로 설정하게되면 세션이 service에서 controller로 돌아올때 세션이 종료되어서 image를 요청할수가 없게된다 하지만 open-in-view를 true로 설정하게된다면 컨트롤에서 디스패쳐로 전해질때 세션이 종료되게 되어 image요청이 가능하게 만들어진다.
@Transactional
DB에 반영되는 함수는 무조건 Transcrtional을 걸어주어야 한다 이유는
우리가 송금 서비스를 만들었다 해보자
밑과같은 데이터가 존재한다
1단계 1번유저가 2번유저에게 5천원을 보냈다 그러면
2단계 2번의 유저는 35000이 되게된다
하지만 만약 1단계는 성공을했다 2단계에서 실패를한다면? 5천원은 그냥 허공으로 증발한것이다
(고객한태 바로 등짝 맞아야함)
이를 방지하기위해 우리는 @Transactional을 사용해야한다
트랜젝셔널의 기능은 하나가 성공하고 하나가 실패하면 전원 롤백시켜버린다 무조건 둘다 성공해야만 커밋을 한다.
알겠으면 만든 사진업로드에 @Transactional을 붙여주러 빨리가자 등짝맞기 싫으면
Select문에도 @Transactional을?
아니 DB에 반영되는 것만 @Transactional을 걸면 되는거 아니었나요?
이유는 여러가지가 있지만 한개만 말씀드리면
user1번정보를 update를 하고싶어서
repository에서 영속성컨텍스트에 자료가 없으면 db로 요청하여 영속성 컨텍스트에 저장이되고 repository에 값이 들어오게 될것이다
이렇게되면 repository와 영속성컨텍스트와 db에는 모두 같은 자료로 동기화가 되어있을것이다
그리고
내가 repository에 user의 이름을 cos로 변경하면 영속성컨택스트에도 cos로 변경되게된다
이름은 service controller로 넘어가는 과정에서 영속성 컨택스트는 변경된 오브젝트를 db에 자동으로 flush하게된다
이때 영속성 컨택스트는 계속 오브젝트가 변경이되었는지 계속 더티체킹을하게된다 그래서 Transactional(readOnly=true)
을 걸어주게 되면 더티체킹을 하지 않게되어 필요없는 일을 할필요가 없게된다.
이외에도 여러 이유가 있지만 이번글에선 여기까지만 알아놓자.
'Spring Boot' 카테고리의 다른 글
SpringBoot + MariaDB 6-3 구독 구독정보 렌더링 (0) | 2023.06.13 |
---|---|
SpringBoot + MariaDB 6-2 구독 구독정보 (스칼라쿼리) (0) | 2023.06.13 |
SpringBoot + MariaDB 5-3 프로필페이지 유저,사진 가져오기(양방향 매핑) Lazy와 Eager의 차이, 사진개수 표현 (0) | 2023.06.12 |
SpringBoot + MariaDB 5-2 프로필페이지 DB에업로드 및 유효성 검사 (1) | 2023.06.12 |
SpringBoot + MariaDB 5-1 프로필페이지 모델만들고 서버에 업로드하기 (외부에 uploadFile 저장하는 이유) (0) | 2023.06.12 |