스프링부트 작동원리
★★영속성 컨텍스트
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 |