2. JPA 시작
1. 객체 매핑 시작
- 클래스와 테이블을 매핑하기 위해 어노테이션을 사용함
import javax.persistence.* @Entity @Table(name="MEMBER") public class Member{ @Id @Column(name = "ID") private String id; @Column(name = "NAME") private String username; // 매핑 정보가 없는 필드 private Integer age; }
- @Entity
- 해당 클래스를 테이블과 매핑한다고 JPA에게 알려줌
- @Entity 어노테이션이 사용된 클래스를
엔티티 클래스
라고 함
- @Table
- 엔티티 클래스에 매핑할 테이블 정보를 알려줌
- 위에서는
name
속성을 사용해서 Member 클래스를 MEMBER 테이블에 매핑함 - 이 어노테이션을 생략하면 클래스 이름을테이블 이름으로 매핑함(정확히는 엔티티 이름을 사용)
- @Id
- 엔티티 클래스의 필드를 테이블의 기본 키
Primary key
에 매핑한다 - @Id 어노테이션이 사용된 필드를
식별자 필드
라고 함
- 엔티티 클래스의 필드를 테이블의 기본 키
- @Column
- 필드를 컬럼에 매핑함
- 여기서는
name
속성을 사용해서 Member 엔티티의 username 필드를 MEMBER 테이블의 NAME 컬럼에 매핑했음
- 매핑 정보가 없는 필드
- 위에서 age 필드와 같이 어노테이션을 생략한 필드는 필드명을 사용해서 컬럼명으로 매핑함
- 대소문자를 구분하는 데이터베이스를 사용하면 명시적으로 매핑해야 함
@Column(name="AGE")
2. persistence.xml 설정
- JPA는 persistence.xml을 사용해서 필요한 설정 정보를 관리함
META-INF/persistence.xml
클래스 패스 경로에 있으면 별도의 설정 없이 JPA가 인식 가능함
<!-- 전체 코드 -->
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1">
<persistence-unit name="jpabook">
<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.id.new_generator_mappings" value="true"/>
</properties>
</persistence-unit>
</persistence>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1">
- XML 네임스페이스와 사용할 버전을 지정, 위와 같이 2.1로 지정
<persistence-unit name="jpabook">
- JPA 설정은 영속성 유닛persistence-unit 부터 시작
- 일반적으로 연결할 데이터베이스당 하나의 영속성 유닛을 등록
- “jpabook”과 같은 고유한 이름을 부여해야 함
<properties> <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
- JPA 표준 속성
<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"/>
- 하이버네이트 속성
hibernate,dialect
: 데이터베이스 방언dialect 설정
- JPA 표준 속성
3. 데이터베이스 방언(Dialect)
- 데이터베이스 방언이란?
- SQL 표준을 지키지 않거나 특정 데이터베이스만의 고유한 기능 또는 형식
- 데이터타입 : MySQL에서는
VARCHAR
, 오라클은VARCHAR2
- 다른 함수명 : 문자열을 자르는 함수를 SQL 표준에서는
SUBSTRING()
, 오라클은SUBSTR()
사용 - 페이징처리 : MySQL은
LIMIT
사용, 오라클은ROWNUM
사용
- 데이터타입 : MySQL에서는
- SQL 표준을 지키지 않거나 특정 데이터베이스만의 고유한 기능 또는 형식
- 데이터베이스의 종속성이 커져서 결국 데이터베이스 교체가 어려워짐
- 하이버네이트를 포함한 대부분의 JPA 구현체들은 이런 문제를 해결하기 위해
데이터베이스 방언 클래스
를 제공함 - H2 : org.hibernate.dialect.H2Dialect
- 오라클 10g : org.hibernate.dialect.Oracle10gDialect
- MySQL : org.hibernate.dialect.MySQL5InnoDBDialect
4. 애플리케이션 개발
public static void Main(String args[]){
// [엔티티 매니저 팩토리] - 생성
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
// [엔티티 매니저] - 생성
EntityManager em = emf.createEntityManager();
// [트랜잭션] - 획득
EntityTransaction tx = em.getTransaction();
try {
tx.begin(); // [트랜잭션] - 시작
logic(em); // 비즈니스 로직 실행
tx.commit(); // [트랜잭션] - 커밋
} catch (Exception e) {
tx.rollback(); // [트랜잭션] - 롤백
} finally {
em.close(); // [엔티티 매니저] - 종료
}
emf.close(); // [엔티티 매니저 팩토리] - 종료
}
- 크게 세 부분으로 나뉘어짐
- 엔티티 매니저 설정
- 트랜잭션 관리
- 비즈니스 로직
4.1 엔티티 매니저 설정
- 엔티티 매니저 팩토리 설정
- 엔티티 매니저 팩토리 생성
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
persistence.xml
에서 이름이jpabook
인 영속성 유닛persistence-unit을 찾아서 엔티티 매니저 팩토리를 생성함- 시간이 오래걸림
- persistence.xml을 읽고, JPA를 동작시키기 위한 기반 객체를 만들고, JPA 구현체에 따라서는 DB 커넥션 풀도 생성함
- 엔티티 매니저 팩토리는 애플리케이션 전체에서 딱 한 번만 생성하고 공유해서 사용해야 함
- 엔티티 매니저 팩토리 생성
- 엔티티 매니저 생성
EntityManager em = emf.createEntityManager();
- 엔티티 매니저를 통해 엔티티를 데이터베이스에 등록/조회/수정/삭제 할 수 있음
- 내부에 데이터베이스 커넥션을 유지하면서 데이터베이스와 통신함
- 데이터베이스 커넥션과 밀접하기 때문에 스레드 간에 공유하거나 재사용하면 안됨
- 엔티티 매니저 팩토리로부터 생성되고 JPA의 대부분의 기능을 제공함
- 종료
em.close(); emf.close();
- 사용이 끝난 엔티티 매니저는 반드시 종료(close) 해야함
- 애플리케이션을 종료할 때 엔티티 매니저 팩토리도 반드시 종료(close) 해야함
4.2 트랜잭션 관리
JPA를 사용하면 항상 트랜잭션 안에서 데이터를 변경해야 함, 트랜잭션 없이 데이터 변경 시 예외 발생함
EntityTransaction tx = em.getTransaction(); // 트랜잭션 API
try{
tx.begin(); // 트랜잭션 시작
logic(em);
tx.commit(); // 트랜잭션 커밋
}catch(Eception e){
tx.rollback(); // 예외 발생 시 트랜잭션 롤백
}
위에처럼 엔티티 매니저(em)에서 트랜잭선 API(tx)를 받아와야 함
4.3 비즈니스 로직
엔티티 매니저를 이용해서 CRUD로 비즈니스 로직 구현하면 됨
- 등록(Create)
Member member = new Member(); member.setId(id); member.setUsername() em.persist(member);
- JPA는 회원 엔티티의 매핑 정보(어노테이션(을 분석해서 다음과 같은 SQL을 만들어 쿼리해줌
INSERT INTO MEMBER (ID, NAME) VALUES ('id1', 'name1')
- 조회(Read)
// 한 건 조회 Member findMember = em.find(Member.class, id); // 목록 조회 List<Member> members = em.createQuery("select m from Member m", Member.class) .getResultList();
find()
메소드는 조회할 엔티티 타입(class)과 데이터베이스 기본 키와 매핑한 식별자 값(@Id)으로 엔티티 하나를 조회해줌JPQL
을 사용해서 검색 조건을 특정할 수 있음
- 수정(Update)
member.setName("newname");
- 단순히 엔티티 객체의 값만 변경해줘도 DB에 아래와 같은 업데이트 쿼리를 알아서 해줌
UPDATE MEMBER SET NAME="newname" WHERE ID="id1"
- 삭제(Delete)
em.remove(member);
- 엔티티 매니저의
remove()
메소드 호출을 통해 엔티티 삭제가 가능함 DELETE FROM MEMBER WHERE ID="id1
4.4 JPQL
위에 조회를 하는 코드 중 하나 이상의 회원을 조회할 때의 코드를 보면
// 목록 조회 List<Member> members = em.createQuery("select m from Member m", Member.class) .getResultList();
- JPA를 사용하면 엔티티 객체 중심의 개발이 가장 큰 장점, 데이터베이스에 대한 처리는 JPA에게 맡겨야 함
- 원래는 조회를 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색해야 함(컬렉션 사용하듯이)
- 그러려면 테이블의 모든 엔티티들을 불러와서 엔티티 객체로 만들어야 검색이 가능해짐
애플리케이션에서 필요로 하는 데이터만 불러오기 위해 결국 검색 조건이 포함된 SQL(=JPQL)을 사용해야 함
- JPQL?
- SQL을 추상화한 객체지향 쿼리 언어
- SQL과 비슷한 문법을 가지며 SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 등 사용 가능
- JPQL vs SQL
- JPQL운 엔티티 객체를 대상으로 쿼리, 즉 클래스와 필드를 대상으로 쿼리함
- SQL은 데이터베이스 테이블을 대상으로 쿼리함
- 위에 조회 코드에서 아래 SQL문 처럼 생긴 부분이 JPQL
select m from Member m
- 여기서
Member
는 엔티티 객체를 뜻하는 것이고, 데이터베이스의 MEMBER 테이블을 의미하는 것이 아님 - JPQL은 엔티티 객체를 대상으로 쿼리하는 것이기 때문에 데이터베이스 테이블과는 독립적
- 사용 방법?
- 엔티티 매니저의
createQuery(JPQL, Type)
호출을 통해 쿼리 객체 생성 - 생성한 쿼리 객체의
getResultList()
메소드 호출
- 엔티티 매니저의