2019년 12월 1일 일요일

김영한님의 JPA프로그래밍 기본기 다지기 메모

김영한님의 JPA 프로그래밍 기본기 강의


  • 회사에 입사한 지 얼마 안됬을 때 사수가 ORM에 대해 한번 훑어보라며, 책을 추천해준 적이 있었다.
    그 때는 정신도 없어서 나중에 봐야겠다... 라고만 생각했는데, 인프런 인강과 다른 블로그에 있는 스프링부트 실습을 따라하면서 JPA 간단하게 경험해볼 수 있었다. 공부해보고 싶기도하고, 토이프로젝트에 적용시켜보고 싶기도 해서 찾아보니 사수가 추천해준 책의 저자께서 직접 설명하는 기본 강의가 유튜브에 있었다!!
    (19.12.01 인프런에 JPA강의도 있다.)
    실습을 통해 이해할 수 있는 좋은 강의였고, 책이나 인프런강의를 통해 더 자세히 공부도 해보고 싶다!

https://www.youtube.com/watch?v=WfrSN9Z7MiA&list=PL9mhQYIlKEhfpMVndI23RwWTL9-VL-B7U

1강 - JPA 소개

  • JPA 기본기 교육임.
  • 애플리케이션은 객체지향언어로 짬. but 데이터베이스는 관계형DB을 사용하고 있음.
    • 객체를 관계형 DB에 관리 -> SQL 필요
  • SQL 중심적인 개발이 이루어짐 -> 무한 반복, 지루한 코드
  • 객체에 필드가 추가될 때? -> 모든 쿼리의 수정이 필요하게 됨
  • 앤티티 신뢰 문제 -> DAO 에서 우리가 필요한 것들을 가져오는게 맞는 지 확인해야함
  • 진정한 의미의 계층 분할이 어렵다
  • SQL에 의존적인개발을 피하기 어렵다
  • 객체를 저장할 때 ?? -> 현실적인 대안 관계형 DB
    • 객체 -> SQL -> RDB
  • 객체와 관계형 데이버베이스의 차이
    • 상속
    • 연관관계
    • 데이터 타입
    • 데이터 식별 방법
-> 객체답게 모델링할 수록 매핑작업이 늘어남(코드가 늘어난다)
  • Java Persistence API : 자바 진영의 ORM 기술 표준
  • ORM
    • Object-relational mapping(객체 관계 매핑)
    • 객체는 객체대로 설계
    • 관계형 데이터베이스는 관계형 데이터베이스대로 설계
    • ORM프레임워크가 중간에서 매핑
    • 대중적인 언어에는 대부분 ORM기술이 존재함
  • JPA를 왜 사용해야 하는가?
    • SQL 중심적인 개발에서 객체 중심으로 개발
    • 생산성 : 간단한 사용가능
    • 유지보수 : 컬러 변동 시 모든 sql 수정 -> 필드만 추가하면됨(sql은 jpa가 처리해줌)
    • 패러다임의 불일치 해결
    • 성능 : 최적화기능(캐시,동일성보장 / 트랜잭션을 지원하는 쓰기 지연 / 지연 로딩)
    • 데이터 접근 추상화와 벤더 독립성
    • 표준
  • ORM은 객체와 RDB 두 기둥 위에 있는 기술

2강 - JPA 기초와 매핑

  • 이번 강의는 실습 위주
  • JPA에서는 크게 중요한 것 두 가지
    1. 객체와 관계형DB와 매핑하는 과정(설계)
    2. 실제 JPA가 어떻게 동작하는지 (영속성 컨텍스 트)
  • H2 데이터 베이스
    • 최고의 실습용 DB
    • 가볍다 (1.5M) (자바에 올려서 배포하기도 한다고 함)
    • 웹용 쿼리 툴 제공
    • MySQL, Oracle 데이터베이스 시뮬레이션 기능
    • 시퀀스, AUTO INCREMENT 기능 지원
  • 메이븐
    • 자바 라이브러리, 빌드 관리
    • 라이브러리 자동 다운로드 및 의존성 관리

객체 매핑하기

  • @Entity : JPA가 관리할 객체 - 엔티티라 한다. (DB랑 매핑할 클래스)
  • @Id : DB PK와 매핑 할 필드
  • persistence.xml
    • JPA 설정 파일
    • /META_INF/persistence.xml 위치
    • javax.persistence로 시작 : JPA 표준 속성
    • hibernate로 시작 : 하이버네이트 전용 속성
  • 데이터베이스 방언
    • JPA는 특정 데이터베이스에 종속적이지 않은 기술
    • 각각의 데이터베이스가 제공하는 SQL 문법과 함수는 조금씩 다르다.
      • 가변문자 : mysql은 varchar, oracle은 varchar2
      • 문자열을 자르는 함수 : SQL 표준은 SUBSTRING(), oracle은 SUBSTR()
      • 페이징 : mysqldms limit , oracle ROWNUM
    • 방언: SQL 표준을 지키지 않거나 특정 데이터베이스만의 고유한 기능
    • Dialect 를 통해 (MySQLDialect, OracleDialect, H2Dialect 등)으로 각 DB용 SQL 생성
    • hibernate.dialect 속성에 지정
      • H2: org.hibernate.dialect.H2Dialect
      • Oracle 10g : org.hibernate.dialect.Oracle10gDialect
      • Mysql : org.hibernate.dialect.MySQL5InnoDBDialect
    • 하이버네이트는 45가지 방언 지원
  • 어플리케이션 개발
    • 준비
    • pom.xml dependency 입력
    • hibernate-entitymanager : 관련 라이브러리 포함되어있음. hibernate core, jpa 2.1 등등 가져옴
    • persistence.xml : jpa이 실행할 때 이파일을 읽어서 DB에 붙고 등등 (부트에선 이 설정파일 없이 알아서 해줌)
    • 앤티티 매니저 팩토리 설정
    • 앤티티 매니저 설정
    • 트랜잭션
    • 비즈니스 로직(CRUD)
// persistence.xml 에 명시된 persistence-unit name정보를 가져와서 로딩하기
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
  • 주의
    • 이 EntityManagerFactory 는 어플리케이션 띄울 때 한번 로딩해야함. 사용자가 실제 비즈니스로직을 태울 때마다 팩토리에서 앤티티매니저를 꺼내서 써야함. 앤티티매니저가 JPA라고 보면됨
    • 앤티티 매니저는 쓰레드간에 공유하면 안된다(사용하고 버려야한다) (데이터베이스 커넥션이 공유될 수 있음.)
    • JPA의 모든 데이터 변경은 트랜잭션 안에서 실행

3강 - 필드와 컬럼 매핑

  • jpa를 통해 테이블을 직접 만들수가 있음.
  • 데이터베이스 스키마 자동 생성하기
    • DDL을 애플리케이션 실행 시점에 자동 생성
    • 테이블 중심 -> 객체중심
    • DB에 맞는 적잘한 DDL 생성
    • 이렇게 생성된 DDL은 개 장비에서만 사용
    • 생성된 DDL은 운영서버에서는 사용하지 않거나, 적절히 다듬은 후 사용
  • hibernate.hbm2ddl.auto
    • create : 기존테이블 삭제 후 다시 생(DROP + CREATE)
    • create-drop : create 와 같으나 종료시점에 테이블 DROP
    • update : 변경분만 반영 (운영 DB에는 사용하면 안됨)
    • validate : 엔티티와 테이블이 정상 매핑되었는지 확인
    • none : 사용하지 않음
    • 운영장비에는 절대 create, create-drop, update 사용하면 안된다.
      • 개발초기단계 create or update
      • 테스트서버 update or validate
      • 스테이징과 운영 validate or none
  • 매핑 어노테이션
    • @Column (DB의 컬럼이름)
      • 가장많이 사용됨
      • name : 필드와 매핑할 테이블의 컬럼이름
      • insertalbe, updatalbe : 읽기전용
      • nullalbe : null 허용여부 결정 , DDL 생성 시 사용
      • unique : 유니크 제약조건, DDL 생성 시 사용
      • columnDefinition, length, precision, scale(DDL)
    • @Temporal (시간관련)
      • 날짜 타입 매핑
      • @Temporal(TemporalType.DATE)
      • localDateTime 써도됨
    • @Enumerated
      • enum타입.
      • 현업에서는 꼭 String을 써야함 (EnumType.STRING). 기본은 ORDINAL(순서임))
    • @Lob
      • CLOB, BLOB 매핑
      • CLOB : String, char[], java.sql.CLOB
      • BLOB : byte[], java.sql.BLOB
      • 이 어노테이션을 String에 쓰면 CLOB, byte에 쓰면 BLOB이 됨
    • @Transient
      • 이 필드는 매핑하지 않는다.
      • 애플리케이션에서 DB에 저장하지 않는 필드
  • 식별자 매핑 어노테이션
    • @Id (직접)
      • IDENTITY : 데이터베이스에 위임. MYSQL
      • SEQUENCE : 데이터베이스 스퀀스 오브젝트 사용. ORACLE
        • @SequenceGenerator
      • TABLE : 키 생성용 테이블 사용, 모든 DB에서 사용
        • @TableGenerator 필요
      • AUTO : 방언에 따라 자동 지정, 기본 값
    • @GeneratedValue
    • 권장하는 식별자
      • 기본 키 제약조건 : null 아님, 유일, 변하면 안된다.
      • 미래까지 이 조건을 만족하는 자연키는 찾기 어렵다. 대리키(대체키)를 사용하자.
      • 예를 들어 주민등록번호도 기본 키로 적절하지 않다.
      • 권장 : Long + 대체키 + 키 생성전략 사용

4강 - 연관관계 매핑

  • '객체지향 설계의 목표는 자율적인 객체들의 협력 공동체 를 만드는 것이다.'
  • 객체를 테이블에 맞추어 데이터 중심으로 모델링하면, 협력 관계 만들 수 없다.
    • 테이블은 외래키로 조인을 사용해서 연관된 테이블을 찾는다.
    • 객체는 참조를 사용해서 연관된 객체를 찾는다.
    • 테이블과 객체 사이에는 이런 큰 간격이 있다.
  • 연관관계 매핑 이론
    • 단반향 매핑
    • 양방향 매핑

5강 - 양방향 매핑

  • 연관관계의 주인과 mappedBy
    • mappedBy : JPA의 멘붕클래스1
    • mappedBy는 처음에는 이해하기 어렵다.
    • 객체와 테이블간에 연관관계를 맺는 차이를 이해해야 한다.
  • 객체와 테이블이 관계를 맺는 차이
    • 객체 연관관계
      • 회원 -> 팀 연관관계 1개 (단방향)
      • 팀 -> 회원 연관관계 1개 (단방향)
    • 테이블 연관관계
      • 회원 <-> 팀 의 연관관계 1개 (양방향)
  • 객체의 양방향 관계
    • 객체의 양방향관계는 사실 양방향관계가 아니라 서로 다른 단방향 관계 2개이다.
    • 객체를 양방향으로 참조하려면 단방향 연관관계를 2개 만들어야 한다.
  • 테이블의 양방향 연관관계
    • 테이블은 외래 키 하나로 두 테이블의 연관관계를 관리
    • MEMBER.TEAM_ID 외래 키 하나로 양방향 연관관계 가짐 (양쪽으로 조인할 수 있다.)
  • 연관관계의 주인 (Owner)
    • 양방향 매핑 규칙
      • 객체의 두 관계중 하나를 연관관계의 주인으로 지정
      • 연관관계의 주인만이 외래 키를 관리(등록,수정)
      • 주인이 아닌 쪽은 읽기만 가능
      • 주인은 mappedBy 속성 X
      • 주인이 아니면 mappedBy 속성으로 주인 지정
  • 누구를 주인으로?
    • 외래 키가 있는 곳을 주인으로 정해라
    • 여기서는 Member.team 연관관계의 주인
  • 양방향 매핑 시 연관관계의 주인에 값을 입력해야 한다.
  • 양방향 매핑의 장점
    • 단방향 매핑만으로도 이미 연관관계 매핑은 완료
    • 양방향 매핑은 반대 방향으로 조회 (객체 그래프 탐색) 기능이 추가 된 것 뿐
    • JPQL에서 역방향으로 탐색할 일이 많음
    • 단방향 매핑을 잘 하고 양방향은 필요할 때 추가해도 됨 (테이블에 영향을 주지않음)
  • 연관관계 매핑 어노테이션
    • 다대일(@ManyToOne)
    • 일대다(@OneToMany)
    • 일대일(@OneToOne)
    • 다대다(@ManyToMany) (현업애선 잘 안씀)
    • @JoinColumn, @JoinTable
  • 상속 관계 매핑 어노테이션 (설명은 책 참조..)
    • @Inheritance
    • @DiscriminatorColumn
    • @DiscriminatorValue
    • @MappedSuperclass (매핑 속성만 상속)
  • 복합키 어노테이션
    • @IdClass
    • @EmbeddedId
    • @Embeddalbe
    • @Mapsld

6강 - JPA 내부 구조

  • 영속성 컨텍스트
    • JPA를 이해하는데 가장 중요한 용어
    • "엔티티를 영구 저장하는 환경" 이라는 뜻
    • EntityManager.persist(entity);
  • 앤티티 매니저 팩토리와 앤티티 매니저
  • 앤티티 매니저? 영속성 컨테스트?
    • 영속성 컨텍스트는 논리적인 개념
    • 눈에 보이지 않는다
    • 앤티티 매니저를 통해서 영속성 컨텍스트에 접근
  • J2SE 환경 : 엔티티 매니저와 영속성 컨텍스트가 1:1
  • J2EE, 스프링 프레임워크 같은 컨테이너 환경 : 앤티티 매니저와 영속성 컨텍스트가 N:1
  • 앤티티의 생명주기
    • 비영속(new/transient) : 영속성 컨텍스트와 전혀 관계가 없는 상태 (객체를 생성만 한 상태)
    • 영속(managed) : 영속성 컨텍스트에 저장된 상태 (객체를 저장한 상태 em.persist(member) )
    • 준영속(detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태 (em.detach)
    • 삭제(removed) : 삭제된 상태 (em.remove(member) )
  • 영속성 컨텍스트의 이점
    • 1차 캐시 (DB가기 전 캐시에서 조회)
    • 동일성(identity) 보장 (1차 캐시때문)
    • 트랜잭션을 지원하는 쓰기 지연 (transactional write-behind)
    • 변경감지(Dirty Checking) (스냅샷과 비교하여 감지)
    • 지연 로딩(Lazy Loading)
  • 플러시 : 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영
  • 플러시 발생
    • 변경 감지
    • 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
    • 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송( 등록, 수정, 삭제 쿼리)
  • 영속성 컨텍스트를 플러시하는 방법
    • em.flush() : 직접호출
    • 트랜잭션 커밋 : 플러시 자동 호출
    • JPQL 쿼리 실행 : 플러시 자동 호출(mybatis 나 스프링 jdbc 를 사용할 경우 flush 를 써야줘야 함)
  • 플러시는!
    • 영속성 컨텍스트를 비우지 않음 (clear가 비움)
    • 영속성 컨텍스트의 변경내용을 데이터베이스에 동기화
    • 트랜잭션이라는 작업 단위가 중요 -> 커밋 직전에만 동기화 하면 됨
  • 준영속 상태
    • 영속 -> 준영속
    • 영속 상태의 엔티티가 영속성 컨텍스트에서 분리(detached)
    • 영속성 컨텍스트가 제공하는 기능을 사용 못함
  • 준영속 상태로 만드는 방법
    • em.detach(entity) : 특정 엔티티만 준영속 상태로 전환
    • em.celar() : 영속성 컨텍스트를 완전히 초기화
    • em.close() : 영속성 컨텍스트를 종료
  • 프록시와 즉시로딩, 지연로딩
    • Member를 조회할 때 Team도 함께 조회해야 할까? : 지연로딩 LAZY을 사용해서 프록시(가짜객체)로 조회
      • 실제 team을 사용하는 시점에 초기화(DB조회)
    • Member와 Team을 자주 함께 사용한다면? : 즉시 로딩 EAGER를 사용해서 함계 조회 (현업에선 보통 LAZY.)
  • 프록시와 즉시로딩 주의
    • 가급적 지연 로딩을 사용
    • 즉시 로딩을 적용하면 예상하지 못한 SQL이 발생
    • 즉시 로딩은 JPQL에서 N+1 문제를 일으킨다.
    • @ManyToOne, @OneToOne은 기본이 즉시로딩 -> LAZY로 설정
    • @OneToMany, @ManyToMany는 기본이 지연로딩

7강 - JPA와 객체지향 쿼리

  • JPA는 다양한 쿼리방법을 지원
    • JPQL
    • JPA Criteria
    • QueryDSL
    • 네이티브 SQL
    • JDBC API 직접 사용, MyBaits, SpringJdbcTemplate 함께 사용
  • JPQL 소개 (객체 대상으로 조회)
    • 가장 단순한 조회 방법
      • EntityManager.find()
      • 객체 그래프 탐색(a.getB().getC())
    • JPA를 사용하면 앤티티 객체 중심으로 개발
    • 문제는 검색쿼리
    • 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색
    • 모든 DB데이터를 객체로 변환해서 검색하는 것은 불가능
    • 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요
    • JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어 제공
    • SQL과 문법 유사 SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 지원
    • JPQL은 엔티티 객체를 대상으로 쿼리 vs SQL은 데이터베이스 테이블을 대상으로 쿼리
    • 테이블이 아닌 객체를 대상으로 검색하는 객체 지향 쿼리
    • SQL을 추상화해서 특정 데이터베이스 SQL에 의존 X
    • JPQL을 한마디로 정의하면 객체지향 SQL
  • JPQL 문법
    • select m from Member m where m.age > 18
    • 엔티티와 속성은 대문자 구문 (Member, username)
    • JPQL 키워드는 대문자 구분안함 (SELECT, FROM , where)
    • 엔티티 이름을 사용, 테이블 이름이 아님(Member)
    • 별칭은 필수 (m)
    • 결과 조회 API
      • query.getResultList() : 결과가 하나 이상, 리스트 반환
      • query.getSingleResult() : 결과가 정확히 하나, 단일 객체 반환 (정확히 하나가 아니면 예외 발생)
    • 파라미터 바인딩 - 이름기준, 위치 기준
      • where m.username=:username
      • query.setParameter("username", usernameParam);
      • where m.username=?1
      • query.setParameter(1, usernameParam);
    • 프로젝션
      • SEELCT m FROM Member m -> 엔티티 프로젝션
      • SELECT m.team FROM Member m -> 엔티티 프로젝션
      • SELECT username,age FROM Member m -> 단순 값 프로젝션
      • new 명령어 : 단순 값을 DTO로 바로 조회
        • SELECT new jpabook.jpql.UserDTO(m.username, m.age) FROM Member m
      • DISTINCT는 중복제거
    • 페이징 API
      • JPA는 페이징을 다음 두 API로 추상화
      • setFirstResult(int startPosition) : 조회 시작 위치(0부터 시작)
      • setMaxResults(int maxResult) : 조회할 데이터 수
      • 집합과 정렬 (COUNT, SUM, AVG, MAX, MIN, GROUP BY, HAVING, ORDER BY)
    • 조인
      • 내부조인 : SELECT m FROM Member m [INNER] JOIN m.team t
      • 외부조인 : SELECT m FROM Member m LEFT [OUTER] JOIN m.team t
      • 세타조인 : SELECT count(m) FROM Member m, Team t WHERE m.username = t.name
      • 페치조인 (많이 씀. LAZY일 경우 필요한경우 이걸로 한번에 조회가능) (List같은거 뿌릴때 안하면 lazy로딩 계속 나감->성능저하)
        • 인티티 객체 그래프를 한번에 조회하는 방법
        • 별칭을 사용할 수 없다.
        • JPQL : SELECT m FROM Member m join fetch m.team
        • SQL : SELECT M.* , T.* , FROM MEMBER T INNER JOIN TEAM t ON M.TEAM_ID = T.ID
    • JPQL 기타
      • 서브쿼리 지원
      • EXISTS, IN
      • BETWEEN, LIKE, IS NULL
    • JPQL 기본함수
      • CONCAT
      • SUBSTRING
      • TRIM
      • LOWER, UPPER
      • LENGTH
      • LOCATE
      • ABS, SQRT, MOD
      • SIZE, INDEX(JPA용도)
      • CASE
    • 사용자 정의 함수 호출
      • 하이버네이트는 사용전 방언에 추가해야한다.
    • Named 쿼리 - 정적 쿼리
      • 미리 정의해서 이름을 부여해두고 사용하는 JPQL
      • 어노테이션, XML에 정의 (요즘엔 어노테이션으로 많이 씀 )
      • 애플리케이션 로딩 시점에 초기화 후 재사용
      • 애플리케이션 로딩 시점에 쿼리를 검증 (오타 등 문법을 애플리케이션 로딩 시 검증가능)

8강 - Spring Data JPA와 QueryDSL의 이해

  • JPA 기반 프로젝트
    • Spring Data JPA
      • 반복되는 CRUD 문제를 세련된 방법을 해결
      • 개발자는 인터페이스만 작성
      • 스프링 데이터 JPA가 구현 객체를 동적으로 생성해서 주입
      • JpaRepository 인터페이스 (공통 CRUD 제공, 제네릭 <엔티티, 식별자> 로 설정)
      • 메서드 이름만으로 JPQL 쿼리 생성 (ㅁㅊ), 정렬, 페이징
        Pagable page = new PageRequest(1,20,new Sort...); Page<Member> result = memeberRepository.findMyName("hello", page);
        
        
        int total = result.getTotalElements(); // 전체 수
        List<Member> members = result.getContent(); // 데이터
        
      • @Query, JPQL 정의 (직접 정의)
      • Web 페이징과 정렬기능
        • 컨트롤러에서 페이징 처리 객체를 바로 받을 수 있음
      • Web 도메인 클래스 컨버터 기능
        • 컨트롤러에서 식별자로 도메인 클래스 찾음
    • QueryDSL
      • SQL, JPQL을 코드로 작성할 수 있도록 도와주는 빌더 API
      • JPA 클리테리아에 비해서 편리하고 실용적임
      • 오픈소스
      • SQL, JPQL의 문제점
        • SQL, JPQL은 문자, Type-check 불가능
        • 해당 로직 실행 전까지 작동여부 확인 불가
      • QueryDSL 장점
        • 문자가 아닌 코드로 작성
        • 컴파일 시점에 문법 오류 발견
        • 코드 자동완성 (IDE 도움)
        • 단순하고 쉬움: 코드모양이 JPQL과 거의 비슷
        • 동적 쿼리
      • QueryDSL 사용 (조인,페이징,동적쿼리 등 다 됌, 자바임!! 자주쓰는 쿼리구문 메서드로 뽑을 수 있음)
        // JPQL
        // select m from Member m where m.age > 18
        
        
        JPAFactoryQuery query = new JPAQueryFactory(em);
        QMember m = QMember.member;
        
        
        List<Member> list = query.selectFrom(m).where(m.age.gt(18)).orderBy(m.name.desc()).fetch();
        
    • Spring JPA, QueryDSL 배민에서 쓰고있음. 저자가 추천함
  • 실무 경험 공유
    • 주문,결제,정상 모두 JPA로 개발됨
    • 테이블 중심에서 객체 중심으로 개발 패러다임이 변화
    • 유연한 데이터베이스 변경의 장점과 테스트
      • Junit 통합 테스트 시에 H2 DB 메모리 로드
      • 로컬 PC에는 H2 DB 서버모드로 실행
      • 개발 운영은 MySQL, Orcle
    • 데이터베이스 변경 경험(개발 도중 MySQL > Oracle 바뀐적도 있다.)
    • 테스트, 통합 테스트시에는 CRUD는 믿고 간다.
    • 빠른 오류 발견
      • 컴파일 시점!
      • 늦어도 애플리케이션 로딩 시점
    • 최소환 쿼리 문법 실수나 오류는 거의 발생하지 않는다.
    • 대분 비즈니스 로직 오류
  • 실무 경험 성능
    • JPA 자체로 인한 성능 저하 이슈는 거의 없음
    • 성능 이슈 대부분은 JPA를 잘 이해하지 못해서 발생
      • 즉시 로딩 : 쿼리가 튐 > 지연로딩으로 변경
      • N+1 문제 > 대부분 페치 조인으로 해결
    • 내부 파서 문제: 2000줄 짜리 동적 쿼리 생성 1초
      • 정적쿼리로 변경(하이버네이트는 파싱된 결과 재사용)
  • 실무 경험 생산성
    • 단순 코딩 시간 줄어듬 > 개발 생성상 향상 > 잉여시간 발생
    • 비즈니스 로직 작성 시 흐름이 끊기지 않음
    • 남는 시간에 더많은 테스트 작성
    • 남는 시간에 기술 공부
    • 남는 시간에 코드 금칠...
    • 팀원 대부분 다시는 과거로 돌아가고 싶어하지 않음
  • 많이 하는 질문
    • ORM 프레임워크를 사용하면 SQL과 데이터베이스는 잘 몰라도 되나요? (둘다 잘해야함 )
    • 성능이 느리진 않나요? (잘쓰면 최적화할 수 있는 부분 많음)
    • 통계쿼리 처럼 매우 복잡한 SQL은 어떻게 하나요? (QueryDSL, 네이티브 쿼리)
    • MyBatis와 어떤 차이가 있나요? (쿼리를 직접 짜야한다)
    • 하이버네이트 프레임워크를 신뢰할 수 있나요? (쿠팡 등 많이 씀)
    • 제 주위에는 MyBatis(iBatis, myBatis)만 사용하는데요?
    • 학습곡선이 높다고 하던데요? (빡세게 공부하고 편하게 살자)
  • 팀 서버 기술 스택
    • Java8
    • Spring Framework(boot)
    • JPA, Hibernate
    • Spring Data JPA
    • QueryDSL
    • Juint, Spock(Test)

댓글 없음:

댓글 쓰기