107
JPA와 모던 자바 데이터 저장 기술 김영한 SK 플래닛 데이터 서비스 개발팀

[162] jpa와 모던 자바 데이터 저장 기술

  • Upload
    naver-d2

  • View
    11.692

  • Download
    18

Embed Size (px)

Citation preview

Page 1: [162] jpa와 모던 자바 데이터 저장 기술

JPA와 모던 자바 데이터저장 기술

김영한

SK 플래닛 데이터 서비스 개발팀

Page 2: [162] jpa와 모던 자바 데이터 저장 기술

김영한SI, J2EE 강사, DAUM, SK 플래닛

저서: 자바 ORM 표준 JPA 프로그래밍

Page 3: [162] jpa와 모던 자바 데이터 저장 기술

contents

1. SQL 중심적인 개발의 문제점2. JPA 소개3. Spring Data JPA4. QueryDSL5. 실무 경험 공유

Page 4: [162] jpa와 모던 자바 데이터 저장 기술

애플리케이션객체 지향 언어 - [Java,Scala, ...]

Page 5: [162] jpa와 모던 자바 데이터 저장 기술

데이터베이스 세계의 헤게모니관계형 DB - [Oracle, MySQL, ...]

Page 6: [162] jpa와 모던 자바 데이터 저장 기술

지금 시대는 객체를

관계형 DB에 관리

Page 7: [162] jpa와 모던 자바 데이터 저장 기술

SQL! SQL!! SQL!!!

Page 8: [162] jpa와 모던 자바 데이터 저장 기술

1.SQL 중심적인 개발의문제점

Page 9: [162] jpa와 모던 자바 데이터 저장 기술

무한 반복, 지루한 코드

CRUD

INSERT INTO …

UPDATE …

SELECT …

DELETE …

자바 객체를 SQL로 ...

SQL을 자바 객체로 ...

Page 10: [162] jpa와 모던 자바 데이터 저장 기술

객체 CURD

INSERT INTO MEMBER(MEMBER_ID, NAME) VALUES

SELECT MEMBER_ID, NAME FROM MEMBER M

UPDATE MEMBER SET …

public class Member { private String memberId; private String name;

...}

Page 11: [162] jpa와 모던 자바 데이터 저장 기술

객체 CURD - 필드 추가

public class Member { private String memberId; private String name; private String tel; ...}

INSERT INTO MEMBER(MEMBER_ID, NAME, TEL) VALUES

SELECT MEMBER_ID, NAME, TEL FROM MEMBER M

UPDATE MEMBER SET … TEL = ?

Page 12: [162] jpa와 모던 자바 데이터 저장 기술

엔티티 신뢰 문제

class MemberService { ... public void process(String id) { Member member = memberDAO.find(id); member.getTeam(); //??? member.getOrder().getDelivery(); // ??? }}

Page 13: [162] jpa와 모던 자바 데이터 저장 기술

계층형 아키텍처진정한 의미의 계층 분할이 어렵다.

Page 14: [162] jpa와 모던 자바 데이터 저장 기술

SQL에 의존적인 개발을 피하기 어렵다.

Page 15: [162] jpa와 모던 자바 데이터 저장 기술

패러다임의 불일치

객체 vs 관계형 데이터베이스

Page 16: [162] jpa와 모던 자바 데이터 저장 기술

‘객체 지향 프로그래밍은 추상화, 캡슐화, 정보은닉, 상속, 다형성 등 시스템의 복잡성을 제어할 수 있는 다양한 장치들을 제공한다.’

­–어느 객체지향 개발자가

Page 17: [162] jpa와 모던 자바 데이터 저장 기술

객체를 영구 보관하는 다양한 저장소

Object

RDB

NoSQL

File

OODB?

Page 18: [162] jpa와 모던 자바 데이터 저장 기술

현실적인 대안은 관계형 데이터베이스

Page 19: [162] jpa와 모던 자바 데이터 저장 기술

객체와 관계형 데이터베이스의 차이

1. 상속

2. 연관관계

3. 데이터 타입

4. 데이터 식별 방법

Page 20: [162] jpa와 모던 자바 데이터 저장 기술

객체를 관계형 데이터베이스에 저장

객체 RDB객체를

SQL로 변환 SQL

Page 21: [162] jpa와 모던 자바 데이터 저장 기술

개발자 ≒ SQL 매퍼

Page 22: [162] jpa와 모던 자바 데이터 저장 기술

상속

[객체 상속 관계] [Table 슈퍼타입 서브타입 관계]

Page 23: [162] jpa와 모던 자바 데이터 저장 기술

Album 저장

1. 객체 분해

2. INSERT INTO ITEM ...

3. INSERT INTO ALBUM …

Page 24: [162] jpa와 모던 자바 데이터 저장 기술

Album 조회

1. 각각의 테이블에 따른 조인 SQL 작성...

2. 각각의 객체 생성...

3. 상상만 해도 복잡

4. 더 이상의 설명은 생략한다.

5. 그래서 DB에 저장할 객체에는 상속 관계 안쓴다.

Page 25: [162] jpa와 모던 자바 데이터 저장 기술

자바 컬렉션에 저장하면?

list.add(album);

Page 26: [162] jpa와 모던 자바 데이터 저장 기술

자바 컬렉션에서 조회하면?

Album album = list.get(albumId);

Item item = list.get(albumId);부모 타입으로 조회 후 다형성 활용

Page 27: [162] jpa와 모던 자바 데이터 저장 기술

연관관계

- 객체는 참조를 사용: member.getTeam()

- 테이블은 외래 키를 사용: JOIN ON M.TEAM_ID = T.TEAM_ID

Page 28: [162] jpa와 모던 자바 데이터 저장 기술

객체를 테이블에 맞추어 모델링

class Member { String id; //MEMBER_ID 컬럼 사용 Long teamId; //TEAM_ID FK 컬럼 사용 //** String username;//USERNAME 컬럼 사용}

class Team { Long id; //TEAM_ID PK 사용 String name; //NAME 컬럼 사용}

Page 29: [162] jpa와 모던 자바 데이터 저장 기술

테이블에 맞춘 객체 저장

INSERT INTO MEMBER(MEMBER_ID, TEAM_ID, USERNAME) VALUES …

class Member { String id; //MEMBER_ID 컬럼 사용 Long teamId; //TEAM_ID FK 컬럼 사용 //** String username;//USERNAME 컬럼 사용}

Page 30: [162] jpa와 모던 자바 데이터 저장 기술

객체다운 모델링class Member { String id; //MEMBER_ID 컬럼 사용 Team team; //참조로 연관관계를 맺는다. //** String username;//USERNAME 컬럼 사용 Team getTeam() { return team; }}

class Team { Long id; //TEAM_ID PK 사용 String name; //NAME 컬럼 사용}

Page 31: [162] jpa와 모던 자바 데이터 저장 기술

객체 모델링 저장

INSERT INTO MEMBER(MEMBER_ID, TEAM_ID, USERNAME) VALUES …

class Member { String id; //MEMBER_ID 컬럼 사용 Team team; //참조로 연관관계를 맺는다. //** String username;//USERNAME 컬럼 사용}

member.getTeam().getId();

Page 32: [162] jpa와 모던 자바 데이터 저장 기술

객체 모델링 조회

public Member find(String memberId) { //SQL 실행 ... Member member = new Member(); //데이터베이스에서 조회한 회원 관련 정보를 모두 입력 Team team = new Team(); //데이터베이스에서 조회한 팀 관련 정보를 모두 입력

//회원과 팀 관계 설정 member.setTeam(team); //** return member;}

SELECT M.*, T.* FROM MEMBER M JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID

Page 33: [162] jpa와 모던 자바 데이터 저장 기술

객체 모델링, 자바 컬렉션에 관리

list.add(member);

Member member = list.get(memberId);Team team = member.getTeam();

Page 34: [162] jpa와 모던 자바 데이터 저장 기술

객체 그래프 탐색

객체는 자유롭게 객체 그래프를 탐색할 수 있어야 한다.

Page 35: [162] jpa와 모던 자바 데이터 저장 기술

처음 실행하는 SQL에 따라 탐색 범위 결정

SELECT M.*, T.* FROM MEMBER M JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID

member.getTeam(); //OK

member.getOrder(); //null

Page 36: [162] jpa와 모던 자바 데이터 저장 기술

처음 실행하는 SQL에 따라 탐색 범위 결정

class MemberService { ... public void process() { Member member = memberDAO.find(memberId); member.getTeam(); //??? member.getOrder().getDelivery(); // ??? }}

Page 37: [162] jpa와 모던 자바 데이터 저장 기술

모든 객체를 미리 로딩할 수는 없다.

상황에 따라 동일한 회원 조회 메서드를 여러벌 생성

memberDAO.getMember(); //Member만 조회

memberDAO.getMemberWithTeam();//Member와 Team 조회

//Member,Order,DeliverymemberDAO.getMemberWithOrderWithDelivery();

Page 38: [162] jpa와 모던 자바 데이터 저장 기술

비교하기String memberId = "100";Member member1 = memberDAO.getMember(memberId);Member member2 = memberDAO.getMember(memberId);

member1 == member2; //다르다.

class MemberDAO { public Member getMember(String memberId) { String sql = "SELECT * FROM MEMBER WHERE MEMBER_ID = ?"; ... //JDBC API, SQL 실행 return new Member(...); }}

Page 39: [162] jpa와 모던 자바 데이터 저장 기술

비교하기 - 자바 컬렉션에서 조회

String memberId = "100";Member member1 = list.get(memberId);Member member2 = list.get(memberId);

member1 == member2; //같다.

Page 40: [162] jpa와 모던 자바 데이터 저장 기술

객체답게 모델링 할수록 매핑 작업만 늘어난다.

Page 41: [162] jpa와 모던 자바 데이터 저장 기술

객체를 자바 컬렉션에 저장 하듯이DB에 저장할 수는 없을까?

Page 42: [162] jpa와 모던 자바 데이터 저장 기술

JPA - Java Persistence API

Page 43: [162] jpa와 모던 자바 데이터 저장 기술

JPA?

- Java Persistence API

- 자바 진영의 ORM 기술 표준

Page 44: [162] jpa와 모던 자바 데이터 저장 기술

ORM?

- Object-relational mapping(객체 관계 매핑)

- 객체는 객체대로 설계

- 관계형 데이터베이스는 관계형 데이터베이스대로 설계

- ORM 프레임워크가 중간에서 매핑

- 대중적인 언어에는 대부분 ORM 기술이 존재

Page 45: [162] jpa와 모던 자바 데이터 저장 기술

JPA는 애플리케이션과 JDBC 사이에서 동작

Page 46: [162] jpa와 모던 자바 데이터 저장 기술

JPA 동작 - 저장

Page 47: [162] jpa와 모던 자바 데이터 저장 기술

JPA 동작 - 조회

Page 48: [162] jpa와 모던 자바 데이터 저장 기술

JPA 소개

EJB - 엔티티 빈(자바 표준)

하이버네이트 (오픈 소스)

JPA(자바 표준)

Page 49: [162] jpa와 모던 자바 데이터 저장 기술

JPA는 표준 명세

- JPA는 인터페이스의 모음

- JPA 2.1 표준 명세를 구현한 3가지 구현체

- 하이버네이트, EclipseLink, DataNucleus

Page 50: [162] jpa와 모던 자바 데이터 저장 기술

JPA 버전

- JPA 1.0(JSR 220) 2006년 : 초기 버전. 복합 키와 연관관계 기능이 부족

- JPA 2.0(JSR 317) 2009년 : 대부분의 ORM 기능을 포함, JPA Criteria 추가

- JPA 2.1(JSR 338) 2013년 : 스토어드 프로시저 접근, 컨버터(Converter), 엔티티 그래

프 기능이 추가

Page 51: [162] jpa와 모던 자바 데이터 저장 기술

JPA를 왜 사용해야 하는가?

- SQL 중심적인 개발에서 객체 중심으로 개발

- 생산성

- 유지보수

- 패러다임의 불일치 해결

- 성능

- 데이터 접근 추상화와 벤더 독립성

- 표준

Page 52: [162] jpa와 모던 자바 데이터 저장 기술

생산성 - JPA와 CRUD

• 저장: jpa.persist(member)

• 조회: Member member = jpa.find(memberId)

• 수정: member.setName(“변경할 이름”)

• 삭제: jpa.remove(member)

Page 53: [162] jpa와 모던 자바 데이터 저장 기술

유지보수 - 기존: 필드 변경시 모든 SQL 수정

public class Member { private String memberId; private String name; private String tel; ...}

INSERT INTO MEMBER(MEMBER_ID, NAME, TEL) VALUES

SELECT MEMBER_ID, NAME, TEL FROM MEMBER M

UPDATE MEMBER SET … TEL = ?

Page 54: [162] jpa와 모던 자바 데이터 저장 기술

유지보수 - JPA: 필드만 추가하면 됨, SQL은 JPA가 처리

public class Member { private String memberId; private String name; private String tel; ...}

INSERT INTO MEMBER(MEMBER_ID, NAME, TEL) VALUES

SELECT MEMBER_ID, NAME, TEL FROM MEMBER M

UPDATE MEMBER SET … TEL = ?

Page 55: [162] jpa와 모던 자바 데이터 저장 기술

JPA와 패러다임의 불일치 해결

1. JPA와 상속

2. JPA와 연관관계

3. JPA와 객체 그래프 탐색

4. JPA와 비교하기

Page 56: [162] jpa와 모던 자바 데이터 저장 기술

JPA와 상속

[객체 상속 관계] [Table 슈퍼타입 서브타입 관계]

Page 57: [162] jpa와 모던 자바 데이터 저장 기술

JPA와 상속 - 저장

jpa.persist(album);

INSERT INTO ITEM ...INSERT INTO ALBUM ...

개발자가 할일

나머진 JPA가 처리

Page 58: [162] jpa와 모던 자바 데이터 저장 기술

JPA와 상속 - 조회

Album album = jpa.find(Album.class, albumId);

SELECT I.*, A.* FROM ITEM I JOIN ALBUM A ON I.ITEM_ID = A.ITEM_ID

개발자가 할일

나머진 JPA가 처리

Page 59: [162] jpa와 모던 자바 데이터 저장 기술

JPA와 연관관계, 객체 그래프 탐색

member.setTeam(team);jpa.persist(member);

연관관계 저장

객체 그래프 탐색Member member = jpa.find(Member.class, memberId);Team team = member.getTeam();

Page 60: [162] jpa와 모던 자바 데이터 저장 기술

신뢰할 수 있는 엔티티, 계층

class MemberService { ... public void process() { Member member = memberDAO.find(memberId); member.getTeam(); //자유로운 객체 그래프 탐색 member.getOrder().getDelivery(); }}

Page 61: [162] jpa와 모던 자바 데이터 저장 기술

JPA와 비교하기

String memberId = "100";Member member1 = jpa.find(Member.class, memberId);Member member2 = jpa.find(Member.class, memberId);

member1 == member2; //같다.

동일한 트랜잭션에서 조회한 엔티티는 같음을 보장

Page 62: [162] jpa와 모던 자바 데이터 저장 기술

JPA의 성능 최적화 기능

1. 1차 캐시와 동일성(identity) 보장

2. 트랜잭션을 지원하는 쓰기 지연(transactional write-behind)

3. 지연 로딩(Lazy Loading)

Page 63: [162] jpa와 모던 자바 데이터 저장 기술

1차 캐시와 동일성 보장

1.같은 트랜잭션 안에서는 같은 엔티티를 반환 - 약간의 조회 성능 향상2. DB Isolation Level이 Read Commit이어도 애플리케이션에서 Repeatable Read 보장

String memberId = "100";Member m1 = jpa.find(Member.class, memberId); //SQLMember m2 = jpa.find(Member.class, memberId); //캐시

println(m1 == m2) //true

SQL 1번만 실행

Page 64: [162] jpa와 모던 자바 데이터 저장 기술

트랜잭션을 지원하는 쓰기 지연 - INSERT

1.트랜잭션을 커밋할 때까지 INSERT SQL을 모음2. JDBC BATCH SQL 기능을 사용해서 한번에 SQL 전송

transaction.begin(); // [트랜잭션] 시작

em.persist(memberA);em.persist(memberB);em.persist(memberC);//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.

//커밋하는 순간 데이터베이스에 INSERT SQL을 모아서 보낸다.transaction.commit(); // [트랜잭션] 커밋

Page 65: [162] jpa와 모던 자바 데이터 저장 기술

트랜잭션을 지원하는 쓰기 지연 - UPDATE

1. UPDATE, DELETE로 인한 로우(ROW)락 시간 최소화2.트랜잭션 커밋 시 UPDATE, DELETE SQL 실행하고, 바로 커밋

transaction.begin(); // [트랜잭션] 시작

changeMember(memberA); deleteMember(memberB); 비즈니스_로직_수행(); //비즈니스 로직 수행 동안 DB 로우 락이 걸리지 않는다.

//커밋하는 순간 데이터베이스에 UPDATE, DELETE SQL을 보낸다.transaction.commit(); // [트랜잭션] 커밋

Page 66: [162] jpa와 모던 자바 데이터 저장 기술

지연 로딩과 즉시 로딩• 지연 로딩: 객체가 실제 사용될 때 로딩• 즉시 로딩: JOIN SQL로 한번에 연관된 객체까지 미리 조회

Member member = memberDAO.find(memberId); Team team = member.getTeam(); String teamName = team.getName();

Member member = memberDAO.find(memberId); Team team = member.getTeam(); String teamName = team.getName();

SELECT M.*, T.* FROM MEMBERJOIN TEAM …

SELECT * FROM MEMBER

SELECT * FROM TEAM

지연 로딩

즉시 로딩

Page 67: [162] jpa와 모던 자바 데이터 저장 기술

ORM은 객체와 RDB 두 기둥위에 있는 기술

Page 68: [162] jpa와 모던 자바 데이터 저장 기술

JPA 기반 프로젝트• Spring Data JPA

• QueryDSL

Page 69: [162] jpa와 모던 자바 데이터 저장 기술

2.Spring Data JPA

Page 70: [162] jpa와 모던 자바 데이터 저장 기술

반복되는 CRUD

public class MemberRepository {

public void save(Member member) {...} public Member findOne(Long id) {...} public List<Member> findAll() {...}

public Member findByUsername(String username) {...}}

public class ItemRepository {

public void save(Item item) {...} public Member findOne(Long id) {...} public List<Member> findAll() {...}}

Page 71: [162] jpa와 모던 자바 데이터 저장 기술

스프링 데이터 JPA 소개

• 지루하게 반복되는 CRUD 문제를 세련된 방법으로 해결

• 개발자는 인터페이스만 작성

• 스프링 데이터 JPA가 구현 객체를 동적으로 생성해서 주입

Page 72: [162] jpa와 모던 자바 데이터 저장 기술

스프링 데이터 JPA 적용 전

public class MemberRepository {

public void save(Member member) {...} public Member findOne(Long id) {...} public List<Member> findAll() {...}

public Member findByUsername(String username) {...}}

public class ItemRepository {

public void save(Item item) {...} public Member findOne(Long id) {...} public List<Member> findAll() {...}}

Page 73: [162] jpa와 모던 자바 데이터 저장 기술

스프링 데이터 JPA 적용 후public interface MemberRepository extends JpaRepository<Member, Long>{ Member findByUsername(String username);}

public interface ItemRepository extends JpaRepository<Item, Long> { //비어있음}

Page 74: [162] jpa와 모던 자바 데이터 저장 기술

스프링 데이터 JPA 적용 후 클래스 다이어그램

Page 75: [162] jpa와 모던 자바 데이터 저장 기술

스프링 데이터 JPA가 구현 클래스 생성

Page 76: [162] jpa와 모던 자바 데이터 저장 기술

공통 인터페이스 기능

• JpaRepository 인터페이스: 공통 CRUD 제공

• 제네릭은 <엔티티, 식별자>로 설정

public interface MemberRepository extends JpaRepository<Member, Long> { //비어있음}

Page 77: [162] jpa와 모던 자바 데이터 저장 기술

공통 인터페이스 기능

Page 78: [162] jpa와 모던 자바 데이터 저장 기술

쿼리 메서드 기능

• 메서드 이름으로 쿼리 생성

• @Query 어노테이션으로 쿼리 직접 정의

Page 79: [162] jpa와 모던 자바 데이터 저장 기술

메서드 이름으로 쿼리 생성

public interface MemberRepository extends JpaRepository<Member, Long> {

Member findByName(String username); }

• 메서드 이름만으로 JPQL 쿼리 생성

Page 80: [162] jpa와 모던 자바 데이터 저장 기술

메서드 이름으로 쿼리 생성 - 사용 코드

List<Member> members = memberRepoitory.findByName(“hello”)

SELECT * FROM MEMBER M WHERE M.NAME = ‘hello’

실행된 SQL

Page 81: [162] jpa와 모던 자바 데이터 저장 기술

이름으로 검색 + 정렬

SELECT * FROM MEMBER M WHERE M.NAME = ‘hello’ ORDER BY AGE DESC

실행된 SQL

public interface MemberRepository extends JpaRepository<Member, Long> { Member findByName(String username, Sort sort); }

Page 82: [162] jpa와 모던 자바 데이터 저장 기술

이름으로 검색 + 정렬 + 페이징

SELECT * //데이터 조회 FROM ( SELECT ROW_.*, ROWNUM ROWNUM_ FROM ( SELECT M.* FROM MEMBER M WHERE M.NAME = ‘hello’ ORDER BY M.NAME ) ROW_ WHERE ROWNUM <= ? ) WHERE ROWNUM_ > ?

실행된 SQL 2가지

public interface MemberRepository extends JpaRepository<Member, Long> { Page<Member> findByName(String username, Pageable pageable); }

//전체 수 조회 SELECT COUNT(1) FROM MEMBER M WHERE M.NAME = ‘hello’

Page 83: [162] jpa와 모던 자바 데이터 저장 기술

이름으로 검색 + 정렬 + 페이징, 사용 코드

Pagable page = new PageRequest(1, 20, new Sort…); Page<Member> result = memberRepoitory.findByName(“hello”, page);

int total = result.getTotalElements(); //전체 수 List<Member> members = result.getContent(); //데이터

전체 페이지수, 다음 페이지 및 페이징을 위한 API 다 구현되어 있음

Page 84: [162] jpa와 모던 자바 데이터 저장 기술

@Query, JPQL 정의

• @Query를 사용해서 직접 JPQL 지정

public interface MemberRepository extends JpaRepository<Member, Long> {

@Query("select m from Member m where m.username = ?1") Member findByUsername(String username, Pageable pageable); }

Page 85: [162] jpa와 모던 자바 데이터 저장 기술

반환 타입

List<Member> findByName(String name); //컬렉션

Member findByEmail(String email); //단건

Page 86: [162] jpa와 모던 자바 데이터 저장 기술

Web 페이징과 정렬 기능

• 컨트롤러에서 페이징 처리 객체를 바로 받을 수 있음• page: 현재 페이지

• size: 한 페이지에 노출할 데이터 건수

• sort: 정렬 조건

@RequestMapping(value = "/members", method = RequestMethod.GET)String list(Pageable pageable, Model model) {}

/members?page=0&size=20&sort=name,desc

Page 87: [162] jpa와 모던 자바 데이터 저장 기술

Web 도메인 클래스 컨버터 기능

• 컨트롤러에서 식별자로 도메인 클래스 찾음

/members/100

@RequestMapping("/members/{memberId}") Member member(@PathVariable("memberId") Member member) { return member; }

Page 88: [162] jpa와 모던 자바 데이터 저장 기술

3.QueryDSL

Page 89: [162] jpa와 모던 자바 데이터 저장 기술

QueryDSL 소개

• SQL, JPQL을 코드로 작성할 수 있도록 도와주는 빌더 API

• JPA 크리테리아에 비해서 편리하고 실용적임

• 오픈소스

Page 90: [162] jpa와 모던 자바 데이터 저장 기술

SQL, JPQL의 문제점

• SQL, JPQL은 문자, Type-check 불가능

• 해당 로직 실행전까지 작동여부 확인 불가

SELECT * FROM MEMBERR WHERE MEMBER_ID = ‘100’

실행 시점에 오류 발견

Page 91: [162] jpa와 모던 자바 데이터 저장 기술

QueryDSL 장점• 문자가 아닌 코드로 작성

• 컴파일 시점에 문법 오류 발견

• 코드 자동완성(IDE 도움)

• 단순하고 쉬움: 코드 모양이 JPQL과 거의 비슷

• 동적 쿼리

Page 92: [162] jpa와 모던 자바 데이터 저장 기술

QueryDSL - 동작원리 쿼리타입 생성

Member.java @Entity

QMember .javaAPT

생성

Page 93: [162] jpa와 모던 자바 데이터 저장 기술

QueryDSL 사용

JPAQuery query = new JPAQuery(em); QMember m = QMember.member; List<Member> list = query.from(m) .where(m.age.gt(18)) .orderBy(m.name.desc()) .list(m);

//JPQL select m from Member m where m.age > 18

Page 94: [162] jpa와 모던 자바 데이터 저장 기술

QueryDSL - 조인

JPAQuery query = new JPAQuery(em); QMember m = QMember.member; QTeam t = QTeam.team; List<Member> list = query.from(m) .join(m.team, t) .where(t.name.eq("teamA")) .list(m);

Page 95: [162] jpa와 모던 자바 데이터 저장 기술

QueryDSL - 페이징 API

JPAQuery query = new JPAQuery(em); QMember m = QMember.member; List<Member> list = query.from(m) .orderBy(m.age.desc()) .offset(10) .limit(20) .list(m);

Page 96: [162] jpa와 모던 자바 데이터 저장 기술

QueryDSL - 동적 쿼리 String name = “member”; int age = 9; JPAQuery query = new JPAQuery(em); QMember m = QMember.member; BooleanBuilder builder = new BooleanBuilder(); if (name != null) { builder.and(m.name.contains(name)); } if (age != 0) { builder.and(m.age.gt(age); } List<Member> list = query.from(m) .where(builder) .list(m);

Page 97: [162] jpa와 모던 자바 데이터 저장 기술

QueryDSL - 이것은 자바다!

return query.from(coupon) .where( coupon.type.eq(typeParam), coupon.status.eq(“LIVE”), marketing.viewCount.lt(markting.maxCount) ) .list(coupon);

서비스 필수 제약조건

Page 98: [162] jpa와 모던 자바 데이터 저장 기술

QueryDSL - 이것은 자바다!

return query.from(coupon) .where( coupon.type.eq(typeParam), isServiceable() ) .list(coupon);

private BooleanExpression isServiceable() { return coupon.status.eq(“LIVE”) .and(marketing.viewCount.lt(markting.maxCount)); }

제약조건 조립가능

- 가독성, 재사용

서비스 필수 제약조건

Page 99: [162] jpa와 모던 자바 데이터 저장 기술

5.실무 경험 공유

Page 100: [162] jpa와 모던 자바 데이터 저장 기술

실무 경험• 테이블 중심에서 객체 중심으로 개발 패러다임이 변화

• 유연한 데이터베이스 변경의 장점과 테스트

• Junit 통합 테스트시에 H2 DB 메모리 모드

• 로컬 PC에는 H2 DB 서버 모드로 실행

• 개발 운영은 MySQL, Oracle

• 데이터베이스 변경 경험(개발 도중 MySQL -> Oracle 바뀐적도 있다.)

• 테스트, 통합 테스트시에 CRUD는 믿고 간다.

Page 101: [162] jpa와 모던 자바 데이터 저장 기술

실무 경험• 빠른 오류 발견

• 컴파일 시점!

• 늦어도 애플리케이션 로딩 시점

• (최소한 쿼리 문법 실수나 오류는 거의 발생하지 않는다.)

• 대부분 비즈니스 로직 오류

Page 102: [162] jpa와 모던 자바 데이터 저장 기술

실무 경험 - 성능• JPA 자체로 인한 성능 저하 이슈는 거의 없음.

• 성능 이슈 대부분은 JPA를 잘 이해하지 못해서 발생

• 즉시 로딩: 쿼리가 튐 -> 지연 로딩으로 변경

• N+1 문제 -> 대부분 페치 조인으로 해결

• 내부 파서 문제: 2000줄 짜리 동적 쿼리 생성 1초

• 정적 쿼리로 변경(하이버네이트는 파싱된 결과 재사용)

Page 103: [162] jpa와 모던 자바 데이터 저장 기술

실무 경험 - 생산성• 단순 코딩 시간 줄어듬 -> 개발 생산성 향상 -> 잉여 시간 발생

• 비즈니스 로직 작성시 흐름이 끊기지 않음

• 남는 시간에 더 많은 테스트 작성

• 남는 시간에 기술 공부

• 남는 시간에 코드 금칠...

• 팀원 대부분 다시는 과거로 돌아가고 싶어하지 않음

Page 104: [162] jpa와 모던 자바 데이터 저장 기술

많이 하는 질문

1. ORM 프레임워크를 사용하면 SQL과 데이터베이스는 잘 몰라도 되나요?

2. 성능이 느리진 않나요?

3. 통계 쿼리처럼 매우 복잡한 SQL은 어떻게 하나요?

4. MyBatis와 어떤 차이가 있나요?

5. 하이버네이트 프레임워크를 신뢰할 수 있나요?

6. 제 주위에는 MyBatis(iBatis, myBatis)만 사용하는데요?

7. 학습곡선이 높다고 하던데요?

Page 105: [162] jpa와 모던 자바 데이터 저장 기술

팀 서버 기술 스택

• Java 8

• Spring Framework

• JPA, Hibernate

• Spring Data JPA

• QueryDSL

• JUnit, Spock(Test)

Page 106: [162] jpa와 모던 자바 데이터 저장 기술

Q&A

Page 107: [162] jpa와 모던 자바 데이터 저장 기술

Thank You