서비스의 책임과 레이지 로딩 설명 및 예제

윤주헌's avatar
Sep 02, 2024
서비스의 책임과 레이지 로딩 설명 및 예제
이체하기를 예시로 들어보자
 
계좌(account)라는 테이블이 있다 계좌번호 1 (5000원 있고 ssar이 들고 있음), 계좌번호2(5000원 있고 cos가 들고 있다)
 
get은 그냥 감
  • 만들어야 할 것(바디) Post요청(먼가를 들고감)
누가 누구에게(계좌 할당된 번호)를 senderAccounID : 1, reseverAccountID : 2
얼마를 줄것인지 AM(amount) : 3000
 
notion image
 
컨트롤러가 0원? -금액 이런 것은 못해서 throw해줌 하지만 6000원이 들어왔어?
컨트롤러는 뒤 레이어를 몰라서 내가 얼마나 있는지 모름 그래서 위임해야함
일단 배운거는 레파지토리인데 그럼 애한테 위임해야할까? 아니다!
  • 레파지 토리 책임
💡
DB관련, Query, 파싱(테이블 데이터를 자기세상 오브잭트로 만들어 주는 것)
즉 애도 책임이 없음
 

서비스 레이어의 발생( 기능 담당 )

그래서 새로운 책임이 필요하다
서비스라는 새로운 레이어가 (기능을 담당한다) 컨트롤러를 외부에 노출하면 (
 
컨트롤러를 인터페이스라 생각한다
컨트롤러는 외부에 공개해야지 사용할 수 있다 그래서
성을 운용하고 잇는데 성 안에 맛있는 팥빵집이 있는데 오후 5시 에 와서 1분안에 들고 가면 돼 → 이게 인터페이스 공표만 하면 된다.
밖 인원들은 오후 그 시간에 가서 빨리 싹 가져가면 됨 외부가 선택할 수 있나? 안됨 컨트롤러가 갑임
인터페이스라 생각하자
 
외부에서 controller 가고 서비스 가서 (나 액셀 받았어 라고 받기만 하면 된다)
 
이체하면 외부에서 요청한다(나 요청할게)
controller에서 요청 받고 바디 데이터를 서비스에 넘긴다
서비스에서 처음 해야할 것 → 계좌가 존재하는지 확인해야 한다(1번 계좌가 db에 있는지)
만약 3번이 들어오면 dB체크하고 없으면 throw던진다.
 
레파지토리에서는 이체하기 메서드가 필요한게 아니고 findById만 있으면 된다
이거를 2번 때리면 된다(조회 해봐야 하거든) 없는데 트랜잭션할 필요 없으니까
 
만약 통과했어
  1. 레파지토리에서 업데이트 2번 쳐야함 처음에는 1번한테 -3000원 업데이트 만약 2번이 하는 곳에서 오류 터지면 1번은 이미 1번은 2000원 남았고 2번은 오류 터져서 5000원으로 롤백된다 문제가 생긴다!! 그래서 서비스에 트랜잭션 걸거다(중간에 throw터지면 트랜잭션 롤백시킨다)(원자성 다 되면 커밋 하나라도 안되면 롤백시켜라)
서비스는 추상적으로 하면 비지니스 로직 담당한다!! 레파지토리의
서비스 기능 쪼개서
  1. 트랜잭션(일의 최소 단위 상대적인 것) 관리
    1. 위의 내용 이체할 때 서비스에서 트랜잭션 거는 것
누구는 화장할 때 로션만 바르면 끝이지만 누구는 이것 저것 다 해야 해서
  1. 비지니스 로직 처리(이게 제일 어렵다 왜? 비지니스 로직을 모르면 처리할 수 없다)
    1. 연말정산 할 때 비과세가 꼭 알아야 하는데 비과세를 몰라 그러면 프로그램 못 짠다
 
컨트롤러는 성이라 하자 실행 되면 스레드가 생성 되는데
해당 스레드가 개개인마다 DB커낵션 객체를 받는다(창고에 접근할 수 있는 권한) 집에 갈 때는 권한을 두고 가야한다.
 
잘 생각해보자 DB접근권한이 성에 있는 동안 다 필요할까? 아니다 DB접근할 때만 필요하다
  • 디폴트 로직
계속 DB접근권한 주고 있는 것
만약 보드를 조회한다 했을 때 만약 컨트롤러가 응답하기 직전에 레이지 로딩 걸림
실무에서는 connection끊어버림 → 서비스 레이어에서 끊어버림
object를 컨트롤러에서 컨버팅하면 JSON이 쫙 된다 getter다 때려진다 이 때 connection열어져 있으면 get 계속 때려버린다 문제가 됨 그래서 꺼야한다
  1. lazy 마무리
 

정리

  • 서비스 책임
  1. 트랜잭션
  1. 비지니스로직
  1. lazy마무리

설명한거 검증

notion image
오류날 수 있으니 조심해 라고 주의 뜬다
예상치 못하게 레이지로딩 걸릴 수 있으니
 
어플리케이션 프로퍼티로 이동
 
다음 테스트
notion image
이러면 404
 
notion image
이러면 제이슨으로 컨버팅 해서 해준다 return시에 (Message 컨버터가 해준다)
적기 전에는 뷰리절브가 일을 해줬다
  • 제이슨이 컨버팅한 증거
notion image
notion image
getter때려 json을 만든다
 
만약 단순 타입이 Board가 아니고 String이라면 리턴에 그냥 문자 적어줌
문자열로 작성하면
text/html으로 응답을 자동으로 한거임
만약
<h1>asdfasdfa</h1> 이러면 브라우저가 해석해서 연다
@GetMapping("/test/board/1") public @ResponseBody String testBoard(){ return "<h1> 글자 진짜 크게 나와</h1>"; }
notion image
 
만약 다시 돌아가서
notion image
리스폰스 해더에 알아서 컨텐트 타입을 application/json으로 받는다
 
이제 레이지 로딩 보여줌
notion image
기본 셀랙트 쿼리 실행 → 유저 셀랙트 함
 
유저정보 필요 없이 데이터 그대로 줘(JSON)
처음에 select잘 했어
notion image
유저 조인한 근거가 없음
리턴할 때 예상치 못한 거를 함 자바 오브젝트를 보여줄 수 없어서 json으로 컨버팅 해야 함
get해서 데이터 값 막 때림 근데 username 하다가 예상치 못한 쿼리가 터져서 문제가 생긴다
이 때 레이지 로딩 걸린다 (꺼내야 넣을 수 있으니까)
notion image
오픈 인 뷰
 
false하면 레이지 로딩 안 걸림 커낵션 버리고 감
notion image
 
결과
notion image
뒤에 다시 찾으러 가지 않음
 
 
리턴할 때 레이지 로딩 걸리는 거임
 
오픈 인 뷰는 DB커낵션(db연결 할 수 있는 허가증 같은 것)을 줘 갔다가 올 때 서비스 레이어에서 커낵션 버리고 컨트롤러로 간다 그래서 기능을 서비스에서 해줘야 한다
 
레이지 로딩 → 최초 한번에 DB에서 찾는게 아닌 또 한번 더 찾으려고 하는 것
 

레이지 로딩 테스트 자료

boardcontroller
@GetMapping("/test/board/1") public @ResponseBody void testBoard() { //여기까지는 레이지 유저 안 땡겨옴 List<Board> boardList = boardRepository.findAll(); System.out.println("---------------------------------"); //보드 리스트를 리턴해버리면? getter다 때려서 json로 바꿔야 함 System.out.println(boardList.get(2).getUser().getPassword()); System.out.println("---------------------------------------------"); }
프로퍼티
spring.jpa.open-in-view=false
Board
//fk 없어서 어노테이션 걸어줘야 한다 @ManyToOne(fetch = FetchType.LAZY) private User user;

레이지 로딩 테스트

  • 트루로 하면
@GetMapping("/test/board/1") public @ResponseBody void testBoard() { //여기까지는 레이지 유저 안 땡겨옴 List<Board> boardList = boardRepository.findAll(); System.out.println("---------------------------------"); //보드 리스트를 리턴해버리면? getter다 때려서 json로 바꿔야 함 System.out.println(boardList.get(2).getUser().getPassword()); System.out.println("---------------------------------------------"); }
결과
notion image
false하면
notion image
 
 
 

정리!!! 테스트 해보자!! 정리필요

  1. Board → User(FK) Lazy전략 순수하게 Board Select 하면 User는 Select 안됨(그냥 fk만 가지고 있다 다른 User데이터는 없음)
  1. OpenlnView = true C-S-R 트루니까 계속 커낵션 가지고 있다
  1. OpenInView = false C-S-R 펄스니까 돌아올 때 서비스에서 커낵션 버리고 간다
전략!
  1. Eager osiv(오픈인뷰) → false controller - lazy loading 이미 둘 다 뽑았어 User객체 들고있다 osiv false 여서 레이지 로딩 안되는데 이미 다 가지고 있어서 상관 x
  1. Lazy → board만 잇고 User없음 osiv(오픈인뷰) → false controller - lazy loading 이러면 user정보 못 뿌림 no session으로 터짐 (서비스에서 lazy loading 해야하는데 못 한거임) DB세션이 없다
  1. Lazy → board만 잇고 User없음 osiv(오픈인뷰) → true controller - lazy loading 이러면 다시 lazy loading (User select발동 근거→ getter → 정상)
그래서 회사에선 lazy loading끈다 그래서 서비스에서 해결해야 한다
 
계속 JSON을 getter때리면서 난리가 난다
 
우리의 전략
lazy, osiv를 끄고 한다
Share article

code-sudal