김영한 강사님의 '자바 ORM 표준 JPA 프로그래밍-기본편' 강의 정리
2022.03.17~03.31 진행
강의를 듣고 개인적으로 정리한 글입니다. 코드와 그림 출처는 김영한 강사님께 있습니다. 문제 있을 시 알려주세요.
프로젝트 생성
- 자바 8이상 (저는 11을 사용하였습니다)
- 빌드 툴은 Maven을 사용
- InteliJ에서 Maven 프로젝트를 새로 생성합니다.
- 라이브러리 설정파일 pom.xml
- JPA 하이버네이트, 데이터베이스 드라이버 등 필요한 의존설정을 추가합니다.
자바 11을 사용했을 때 오류 해결방법 : pom.xml에 다음 코드를 추가
<!-- 자바11 에러 해결-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
JPA 설정하기 - persistence.xml
- JPA 설정 파일 /META-INF/persistence.xml 생성
- persistence-unit name으로 이름 지정
- javax.persistence로 시작: JPA 표준 속성 → 다른 JPA 구현 라이브러리를 써도 적용됨
- hibernate로 시작: 하이버네이트 전용 속성 → 다른 라이브러리로 바꿀 시 전부 교체
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2"
xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="hello">
<properties>
<!-- 필수 속성 -->
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="javax.persistence.jdbc.user" value="sa"/>
<property name="javax.persistence.jdbc.password" value=""/>
<property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<!-- 옵션 -->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.use_sql_comments" value="true"/>
<!--<property name="hibernate.hbm2ddl.auto" value="create" />-->
</properties>
</persistence-unit>
</persistence>
데이터베이스 방언 - dialect
데이터베이스가 제공하는 SQL 문법과 함수는 각자 조금씩 다르다. JPA로는 데이터베이스 방언을 지정해서 특정 데이터베이스에 종속되지 않게 개발할 수 있다. 하이버네이트는 40가지 이상의 데이터베이스 방언을 지원한다.
- 방언(사투리): SQL 표준을 지키지 않는 특정 데이터베이스만의 고유한 기능
- hibernate.dialect 속성에 지정
- H2 : org.hibernate.dialect.H2Dialect
- Oracle 10g : org.hibernate.dialect.Oracle10gDialect
- MySQL : org.hibernate.dialect.MySQL5InnoDBDialect
persistence.xml에 다음 코드를 적용하면 H2 데이터베이스 방언이 지정된다.
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
JPA 구동방식
Persistence 클래스가 설정정보를 읽어서 EntityManagerFactory 클래스를 만들고 필요할 때마다 EntityManager를 찍어내서 돌린다.
❗주의
- 엔티티 매니저 팩토리는 하나만 생성해서 애플리케이션 전체에서 공유한다.
- 엔티티 매니저는 쓰레드간에 절대 공유X (사용하고 버려야 한다).
- JPA의 모든 데이터 변경은 트랜잭션 안에서 실행
- 트랜잭션 안건다고 해도 DB는 내부적으로 트랜잭션 단건 쿼리 처리를 해서 되긴 됨, 하지만 해야함!!
실습
객체와 테이블을 생성하고 매핑하기
@Entity //JPA가 인식
public class Member {
@Id //PK
private Long id;
private String name;
}
public class JpaMain {
public static void main(String[] args){
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
//App 로딩 시점에 딱 하나만 만들어놔야한다. (DB당 하나)
EntityManager em = emf.createEntityManager();
//실제 트랜잭션 단위(DB 커넥션을 얻고-쿼리수행-끊김) 로직이 수행 될 때마다 만든다
EntityTransaction tx = em.getTransaction();
tx.begin();
//JPA에서 데이터를 변경하는 작업은 트랜잭션안에서 수행되어야 함
try{
//생성
// Member member = new Member();
// member.setId(1L);
// member.setName("HelloA");
// em.persist(member);
//조회
Member findMember = em.find(Member.class, 1L);
// System.out.println("findMember.id = " + findMember.getId());
// System.out.println("findMember.name = " + findMember.getName());
//삭제
// em.remove(findMember);
//수정
findMember.setName("HelloJPA"); //변경만해도 DB에 반영됨
tx.commit();
} catch(Exception e){
tx.rollback();
} finally {
em.close(); //엔티티 매니저를 꼭 닫아줘야 한다!
}
//JPA에서 데이터를 변경하는 작업은 트랜잭션안에서 수행되어야 함. DB커넥션 반환
emf.close(); //실제 App이 완전히 끝나면 닫아준다.
//WAS가 내려갈 때 커넥션 풀링이나 그런게 다 내부적으로 릴리즈가 됨.
}
}
실무에서는 위 코드를 스프링이 다해준다.
- 회원 등록, 단 건 조회, 삭제
- 회원 수정
- JPA를 통해서 엔티티를 가져오면 JPA가 관리한다.
- 변경이 되었는지 트랜잭션을 commit하는 시점에서 dirty checking한다.
- 변경되었으면 update 쿼리를 만들어서 날린다.
JPQL이 필요한 이유
가장 단순한 조회 방법은 다음과 같다.
- EntityManager.find()
- 객체 그래프 탐색(a.getB().getC())
그런데... 나이가 18살 이상인 회원을 모두 검색하고 싶다면? 현업에서는 수백개의 여러 테이블을 필요하면 조인도 해야하고.. 원하는 데이터를 최적화해서 가져와야하고, 필요하면 통계성 쿼리도 날려야 한다.
JPA를 사용하면 엔티티 객체를 중심으로 개발을 한다.
- 문제: 검색 쿼리
- JPA는 검색을 할 때 테이블이 아닌 엔티티 객체를 대상으로 검색한다. 즉 DB데이터를 객체로 변환한 다음 검색한다.
- 그런데 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능할뿐더러 DB에 종속적으로 설계가 된다.
⇒ 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요하다.
- 해결: JPA가 제공하는 SQL을 추상화한 객체 지향 쿼리 언어, JPQL를 쓰자.
- SQL과 문법이 유사하다. SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 지원 (즉 객체 지향 SQL)
- SQL을 추상화해서 특정 데이터베이스 SQL에 의존X →방언을 바꿔도 코드를 바꿀 필요가 없다!
JPQL 실습
JPQL로 전체 회원 검색
List<Member> result = em.createQuery("select m from Member as m", Member.class) .getResultList();
//테이블이 아니라 Member 객체를 대상으로 쿼리를 날린다.
JPQL로 페이징
List<Member> result = em.createQuery("select m from Member as m", Member.class) .setFirstResult(5) .setMaxResults(8) .getResultList();
❗ JPQL과 SQL의 차이점 짚고 넘어가자.
- JPQL은 엔티티 객체를 대상으로 쿼리
- SQL은 데이터베이스 테이블을 대상으로 쿼리
'Web > JPA' 카테고리의 다른 글
[Inflearn] JPA - 값 타입(작성전) (0) | 2022.05.11 |
---|---|
[Inflearn] JPA - 객체지향 쿼리 언어 (0) | 2022.03.31 |
[Inflearn] JPA - 엔티티매핑 (0) | 2022.03.22 |
[Inflearn] JPA - 영속성관리 (0) | 2022.03.22 |
[Inflearn] ORM, JPA란 무엇인가 (0) | 2022.03.21 |