2021-08-25-TIL
JPA 인프런 강의
H2 데이터베이스
강의 실습은 H2를 DB로 쓴다. H2 공식 사이트는 H2를 JDBC API를 쓰는 오픈소스 Java SQL 데이터베이스로 소개하며, 임베디드 모드와 서버 모드, 디스크 기반과 인메모리 DB, 브라우저 기반 콘솔을 주요 기능으로 든다. 임베디드 모드는 애플리케이션과 같은 JVM 안에서 DB를 여는 방식이라 가장 빠르지만 한 번에 하나의 JVM에서만 열 수 있고, 서버 모드는 TCP/IP로 접속하므로 느린 대신 여러 애플리케이션이 같은 DB에 붙을 수 있다.
실습할 때의 오류
실습 중에 막힌 부분은 인프런 질문 게시판에서 같은 증상을 찾아 해결했다.
Persistence.createEntityManagerFactory("hello")를 호출하자마자java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException이 나는 경우: 강사 답변은 Java 11부터 해당 라이브러리가 기본 자바에서 빠졌기 때문이라는 것이다. JEP 320에 따라 Java SE 11에서java.xml.bind(JAXB)를 포함한 Java EE 모듈이 제거되었으므로,javax.xml.bind:jaxb-api의존성을 직접 추가하면 된다.- H2 콘솔에서 연결을 누르면
Database "..." not found, either pre-create it or allow remote database creation오류가 나는 경우: H2 튜토리얼에 따르면 임베디드 URL로 접속하면 DB가 없을 때 새로 만들지만, TCP 연결이나 웹 콘솔을 통한 원격 생성은 기본적으로 막혀 있다. 그래서 처음 한 번은 임베디드 URL(jdbc:h2:~/test)로 접속해 DB 파일을 만든 뒤 서버 모드 URL로 접속한다.
JPQL vs QueryDSL
Querydsl 강의 게시판에서 실무에서 JPQL과 Querydsl을 같이 쓰는지 묻는 질문을 찾아봤다. 강사의 답은 단순한 기능은 스프링 데이터 JPA로 처리하고, 단순한 JPQL 몇 개면 @Query로 인터페이스에 바로 쓰고, 조금 복잡해지거나 동적 쿼리가 필요하면 커스텀 리포지토리를 만들어 Querydsl을 쓴다는 것이다. 스프링 데이터 JPA와 Querydsl을 함께 쓰려면 커스텀 리포지토리를 추가해야 해서, 쿼리 한두 개 때문에 그 비용을 들이기 애매할 때 @Query가 편하다는 설명이다.
강의 진도와 JPA가 어려운 이유
961분 / 7 = 137분 -> 약 2시간씩
JPA가 어려운 이유
- 객체를 올바르게 설계하고 테이블을 매핑하는 게 어렵다.
- JPA의 내부 동작 방식을 이해하지 못해서 장애 상황에 대처하지 못한다.
- JPA가 어떤 SQL을 만들어내는지
- JPA가 어떤 시점에, 언제 실행되는지
관계형 DB와 SQL 중심 개발의 문제
대부분 관계형 db를 사용, 따라서 객체를 관계형 db에 저장해야 한다.
문제는 sql인데 DB는 sql을 알아듣기 때문에 이로 인한 지루한 문제가 발생한다.
- 무한반복, 지루한 코드 -> CRUD, 물론 마이바티스나 jdbc template을 쓰면 조금 낫지만 쿼리를 작성해야 한다는 점은 마찬가지이다. 현타가 올 것이다..
- 객체 crud를 완료하고 필드 하나가 추가되었다면 쿼리에도 일일이 추가해야 한다. 그리고 에러가 나서 보면 쿼리 중 일부에 빠뜨릴 가능성이 높다.
패러다임의 불일치 문제가 있다. 관계형 db와 객체 지향의 패러다임이 다르다. 객체를 영구보관하는 다양한 저장소가 있지만, 결국 RDB를 써야 한다. 결국 객체 -> RDB를 매핑해야 하는 것인데, 개발자가 sql 매퍼의 역할만 계속 하게 된다.
객체와 관계형 db의 차이: 상속
객체의 상속관계와 가장 유사한 테이블 모델이 슈퍼타입 서브타입 관계이다.
앨범을 조회하려면 item-album 조인… 나머지도 마찬가지다
자바 컬렉션에서 조회하려면?
부모타입으로 조회 후 다형성을 활용하여 하위 타입으로 읽으면 된다.
연관관계
객체는 참조를 사용하여 참조하므로 한방향이다.
테이블은 조인하여 양방향으로 참조가 가능하다.
탐색 범위
자유롭게 탐색할 수 있는가? 아니다. 처음 select 해서 가져온 만큼만 가지고 있다.
엔티티 신뢰 문제
탐색 범위가 처음 실행한 SQL에 묶여 있으면, 조회 메서드가 돌려준 엔티티의 연관 객체가 채워져 있는지 코드만 보고는 알 수 없다. 결국 DAO가 어떤 SQL을 실행하는지 직접 열어 보기 전에는 반환된 엔티티를 믿고 쓸 수 없다는 것이 강의에서 말하는 엔티티 신뢰 문제다.
모든 객체를 미리 다 로딩할 수는 없다
계층형 아키텍처 진정한 의미의 계층 분할이 어렵다.
JPA 소개
3강 JPA 소개
JPA 동작
중요한 점은 패러다임 불일치를 해결해준다는 점
JPA를 왜 사용해야 하는가
생산성 - JPA와 CRUD
반복되던 CRUD SQL을 개발자가 쓰지 않아도 된다는 점이 첫 번째 이유다. 저장, 조회, 수정, 삭제를 컬렉션을 다루듯 메서드로 처리하고, SQL은 JPA가 매핑 정보를 보고 만든다.
유지보수
연락처 컬럼 추가하는 경우 -> db에 추가 후 필드에 추가하면 끝
신뢰할 수 있는 엔티티, 계층
JPA를 통해 그래프 탐색을 자유롭게 가능 -> 지연로딩을 통해서 없더라도 다시 알아서 가져온다
JPA의 성능 최적화 기능
성능 최적화 기법 두 가지 -> 모아서 쏘는 버퍼링과 저장해두는 캐싱
- 1차 캐시와 동일성 보장
사실 별 도움 안 됨
DB isolation level이 read committed여도 애플리케이션에서 repeatable read 보장
트랜잭션을 지원하는 쓰기 지연 - insert
- 트랜잭션을 커밋할 때까지 insert sql을 모음
- jdbc batch sql 기능을 사용해서 한 번에 sql 전송
Hibernate 사용자 가이드도 Session(JPA의 EntityManager)이 영속성 컨텍스트를 1차 캐시로 유지하며, 이 컨텍스트가 대체로 repeatable read 수준으로 동작한다고 설명한다. 같은 트랜잭션 안에서 같은 식별자로 두 번 조회하면 같은 객체를 돌려받는 것이 이 때문이다.
지연 로딩과 즉시 로딩
지연로딩은 필요할 때 값을 가져옴
무조건 같이 사용하는 데이터면 그냥 즉시로딩으로 한 번에 가져오는 게 낫다.
JPA는 옵션 하나로 껐다 켤 수 있다. 김영한님은 지연로딩으로 모두 작성한 후에 최적화가 필요할 때만 해당 부분을 즉시로딩으로 변경하는 식으로 개발한다.
ORM은 객체와 RDB 두 기둥 위에 있는 기술이다. RDB가 훨씬 중요한 기술이며 이는 잘 바뀌지 않으므로 필수적으로 학습해야 한다.
엔티티 매니저 팩토리와 엔티티 매니저
엔티티 매니저 팩토리는 하나만 생성해야 하며 엔티티 매니저는 절대 공유해서는 안 된다!
Hibernate 문서의 설명도 같다. SessionFactory(EntityManagerFactory)는 스레드 안전하지만 생성 비용이 매우 커서 DB 하나에 하나만 두고, Session(EntityManager)은 한 스레드가 짧게 쓰는 작업 단위(Unit of Work) 객체라 여러 스레드가 동시에 쓰도록 설계되지 않았다.
JPQL은 테이블이 아닌 객체를 대상으로 검색하는 객체 지향 쿼리이다!!!!!
참고한 자료외부 출처 8
외부 출처
- H2 Database EngineH2
- FeaturesH2: 임베디드 모드와 서버 모드
- TutorialH2: 원격 DB 생성이 기본으로 막혀 있다는 설명
- Exception 오류 확인 요청
- h2 연결이 되지 않습니다.
- Querydsl과 jpql을 선택하는 차이가 궁금합니다.
- JEP 320: Remove the Java EE and CORBA Modules
- Hibernate ORM User Guide
댓글
아직 댓글이 없습니다