본문 바로가기
springboot 수업일지

11일차 영속성 컨텍스트-LAZY,EAGER전략

by wannabe 2021. 7. 5.

스프링부트 작동원리

★★영속성  컨텍스트 

1. User 정보 가져오기

1-1) EAGER 전략

EAGER 전략으로 하면??(Default는 Lazy전략) 

test/user/1로 요청하면 join해서 List<Post>도 가져와준다!!! 

기본전략(LAZY)으로 하면? 안가져온다. 나중에 getter로 하면? 그때서야 다시 select해서 가져온다=>LAZY 전략

★위 함수에서 Return타입을 User에서 String 으로 바꿔준 이유는???

 MessageConverter(@RestController)는 JSON으로 변환하기 위해 Getter함수를 다 때려주니까(LAZY전략이라도 getter로 List<Post>를 가져와준다)!! EAGER, LAZY전략을 구분하기 힘들다. 그래서 String 리턴으로 해서 Getter함수 때리지 않게 하고 어떤 쿼리가 실행되는지 확인한다!!!!

 

위 함수 호출:  http://localhost:8000/test/user/1

결과는??? EAGER 전략

Hibernate: select user0_.id as id1_1_0_, user0_.address as address2_1_0_, user0_.email as email3_1_0_, user0_.password as password4_1_0_, user0_.username as username5_1_0_, posts1_.user_id as user_id4_0_1_, posts1_.id as id1_0_1_, posts1_.id as id1_0_2_, posts1_.content as content2_0_2_, posts1_.title as title3_0_2_, posts1_.user_id as user_id4_0_2_ from user user0_ left outer join post posts1_ on user0_.id=posts1_.user_id where user0_.id=?

 

1-2) 다음으로, LAZY 전략

위 함수 호출:  http://localhost:8000/test/user/1

Hibernate: select user0_.id as id1_1_0_, user0_.address as address2_1_0_, user0_.email as email3_1_0_, user0_.password as password4_1_0_, user0_.username as username5_1_0_ from user user0_ where user0_.id=?
1
Hibernate: select posts0_.user_id as user_id4_0_0_, posts0_.id as id1_0_0_, posts0_.id as id1_0_1_, posts0_.content as content2_0_1_, posts0_.title as title3_0_1_, posts0_.user_id as user_id4_0_1_ from post posts0_ where posts0_.user_id=?
2

 

2. Post 정보 가져오기

2-1) 기본전략 : EAGER

기본전략 : EAGER

test/post/1으로 때리면? join해서 User를 가져온다.

Hibernate: select post0_.id as id1_0_0_, post0_.content as content2_0_0_, post0_.title as title3_0_0_, post0_.user_id as user_id4_0_0_, user1_.id as id1_1_1_, user1_.address as address2_1_1_, user1_.email as email3_1_1_, user1_.password as password4_1_1_, user1_.username as username5_1_1_ from post post0_ left outer join user user1_ on post0_.user_id=user1_.id where post0_.id=?

 

2-2) LAZY전략으로 해보자

test/post/1으로 때리면? User객체를 가져오지 않는다!

Hibernate: select post0_.id as id1_0_0_, post0_.content as content2_0_0_, post0_.title as title3_0_0_, post0_.user_id as user_id4_0_0_ from post post0_ where post0_.id=?

 

 

LAZY전략에서 User객체를 가져오게 해보자!

결과는???

Hibernate: select post0_.id as id1_0_0_, post0_.content as content2_0_0_, post0_.title as title3_0_0_, post0_.user_id as user_id4_0_0_ from post post0_ where post0_.id=?
1
Hibernate: select user0_.id as id1_1_0_, user0_.address as address2_1_0_, user0_.email as email3_1_0_, user0_.password as password4_1_0_, user0_.username as username5_1_0_ from user user0_ where user0_.id=?
2

 

3. jpa.open-in-view

1) open-in-view: false

/test/user/1 -> getPosts().get(0).getTitle(); 하면?? lazy로딩 안되므로 에러(no session)

http://localhost:8000/test/user/1 때리면?? 다음과 같은 에러가 뜬다. no Session!!

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.korea.dbapp.domain.user.User.posts, could not initialize proxy - no Session

 

해결책1> 전략 Eager로 변경해서!!!

위 함수 그대로 해서!!

http://localhost:8000/test/user/1 때리면?? 에러안뜸 EAGER전략으로 JOIN을 해서 가져옴!
Hibernate: select user0_.id as id1_1_0_, user0_.address as address2_1_0_, user0_.email as email3_1_0_, user0_.password as password4_1_0_, user0_.username as username5_1_0_, posts1_.user_id as user_id4_0_1_, posts1_.id as id1_0_1_, posts1_.id as id1_0_2_, posts1_.content as content2_0_2_, posts1_.title as title3_0_2_, posts1_.user_id as user_id4_0_2_ from user user0_ left outer join post posts1_ on user0_.id=posts1_.user_id where user0_.id=?


해결책2> open-in-view: true  / LAZY전략 그대로

위 함수 그대로 해서!!

http://localhost:8000/test/user/1 때리면?? 오류 안뜸! LAZY 전략으로 두번 SELECT가 일어난다.

Hibernate: select user0_.id as id1_1_0_, user0_.address as address2_1_0_, user0_.email as email3_1_0_, user0_.password as password4_1_0_, user0_.username as username5_1_0_ from user user0_ where user0_.id=?
1
Hibernate: select posts0_.user_id as user_id4_0_0_, posts0_.id as id1_0_0_, posts0_.id as id1_0_1_, posts0_.content as content2_0_1_, posts0_.title as title3_0_1_, posts0_.user_id as user_id4_0_1_ from post posts0_ where posts0_.user_id=?
2

 

2) toString 테스트

open-in-view: false 인 상태!

 

http://localhost:8000/test/user/1 때리면??

결과는?? 콘솔창에 다음과 같이 에러뜸

org.hibernate.LazyInitializationException: could not initialize proxy [com.korea.dbapp.domain.user.User#1] - no Session

▷해결책?? open-in-view: true 로해보자!!

결과는?? java.lang.StackOverflowError: null

왜?? toString 함수가 호출될때, 서로(User,Post) 무한참조를 하니까!!

▷추가 해결책??

User클래스에 toString 함수에서 Posts를 리턴하지 않게!

결과는???

또는 

Post클래스에 toString함수에서 User를 리턴하지 않게!

결과는??? 

User [id=1, username=ssar, password=1234, email=null, address=null, 

       posts=[Post [id=1, title=제목1, content=내용1],

                 Post [id=2, title=제목2, content=내용2],

                 Post [id=3, title=제목3, content=내용3]]]

 

<정리>

view는 앞에 보이는 애 

view단까지 open한다!! 즉, session을 view단까지 

원래는, request할때 session이 열린다. session이 열려있어야 db커넥션해서 select,insert,update해줄 수 있다.

Controller단을 view라고 한다. 

즉, view단까지 세션을 유지하는것

controller에서 session이 유지되니까, lazy로딩이 가능하게되는 것

전통적인 스프링에서는 controller돌아오기 직전에 session이 죽어버렸다. 그래서 lazy로딩이 안되었다.

 그런데, open-in-view를 설정해놓으면??? lazy로딩이 가능하다!!!!!!!

open in view가 없다면???? EAGER전략으로 바꾼다!!

'springboot 수업일지' 카테고리의 다른 글

12일차 주소API(2)  (0) 2021.07.06
11일차 주소API  (0) 2021.07.05
10일차 현재 프로젝트 Git으로  (0) 2021.07.02
10일차 Git영역 개념 및 실습  (0) 2021.07.02
9일차 DB JOIN개념/ORM 기법 실습  (0) 2021.07.01