JPA 기초와 매핑
JPA를 공부하면서 정리를 한 내용들 입니다.
| -참고 김영한 개발자님 : [토크ON세미나] JPA 프로그래밍 기본기 다지기 - JPA 기초와 매핑 | T아카데미 | 
2강. JPA 기초와 매핑
1.JPA의 중요한 것
- 객체와 관계형 DB의 매핑 과정은?
- 실제 JPA는 어떻게 동작하는가?
2.객체 매핑하기
- @Entity : JPA가 관리할 객체입니다. ☆중요
- @Id : DB PK와 매핑 할 필드입니다.
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Member {
    @Id
    private Long id;
    private String name;
    ....
}
create table Member(
   int bigint not null,
   name varchar(255),
   primary key(id)
3.persistence.xml
- JPA 설정 파일입니다.
- JPA는 기본적으로 persistence.xml파일이 필요합니다.
- /META-INF/persistence.xml에 위치합니다.
- javax.persistence로 시작 합니다.: JPA 표준 속성
- hibernate로 시작 합니다. : 하이버네이트 전용 속성
형태는 아래와 같이 생겼습니다.
h2 데이터베이스와 하이버네이트를 사용한다는 가정하에 작성된 내용입니다.
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.2">
    <persistence-unit name="hello">
        <class>com.tacademy.jpaex.entity.Member</class> <!-- gradle에서만 추가 -->
        <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.user_sql_comments" value="true"/>
            <!-- <property name="hibernate.hbm2ddl.auto" value="create"/>-->
        </properties>
    </persistence-unit>
</persistence>
4.데이터 베이스 방언
- JPA는 특정 DB에 종속적이지 않은 기술입니다.
- 각각의 DB가 제공하는 SQL 문법과 함수는 조금씩 다릅니다.
    - 가변 문제 : MySQL은 VARCHAR, Oracle은 VARCHAR2
- 문자열을 자르는 함수 : SQL 표준은 SUBSTRING(), Oracle은 SUBSTR()
- 페이징 : MySQL은 LIMIT, Oracle ROWNUM
 
- 방언이란 SQL 표준을 지키지 않거나 특정 데이터베이스만의 고유한 기능 입니다.
- 방언이 다르기 때문에 DB를 변경하는 작업이 쉽지가 않으나 
 JPA는 모든 방언에 맞춰서 다르게 쿼리를 만들어주기 때문에 쉽게 DB를 변경할 수 있습니다.
- hibernate.dialect 속성에 지정합니다
    - H2, Oracle 10g, MySQL …
 
- 하이버네이트는 45가지 방언 지원해줍니다.
애플리케이션 개발
엔티티 매니저 설정

- 
    EntityManageFactory는 애플리케이션 실행 중 한번만 실행이 됩니다. 
- 
    사용할때마다 EntityManager가 처리하게 된다. 
실습
1.Maven 프로젝트 생성
2.Dependency 추가
pom.xml에 다음과 같이 dependency를 추가해줍니다.
    <dependencies>
        <!-- Hibernate -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.4.0.Final</version>
        </dependency>
        <!-- H2 Database -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.197</version>
            <!-- <scope>test</scope> -->
        </dependency>
    </dependencies>
3.JPA 설정 파일 생성
resources/META-INF/persistence.xml (만약 경로가 다르면 실행 시 다음과 같은 에러가 발생함)
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.2">
<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"/>
</properties>
</persistence-unit>
</persistence>
4.Member class 생성
package hellojpa.entity;
import javax.persistence.Entity; // JPA표준이므로 persistence를 선택해야합니다.
import javax.persistence.Id;
@Entity
public class Member {
    @Id // PK값이므로 이 어노테이션으로 매핑해줘야함
    private Long id;
    private String name;
    // getter setter를 생성
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
5.Main class 및 method 생성
package hellojpa;
import hellojpa.entity.Member;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class Main {
public static void main(String[] args) {
// 1. EntityManagerFactory 생성
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        // 2. EntityManagerFactory를 통해 EntityManager 생성
        EntityManager em = emf.createEntityManager();
        // 3. EntityManager를 통해 트랜잭션 획득
        EntityTransaction tx = em.getTransaction();
        // 4. 트랜잭션 시작
        tx.begin();
        // 5. 새로 삽입할 Member 객체 생성
        Member member = new Member();
        member.setId(100L);
        member.setName("안녕하세요.");
        // 6.EntityManager를 통해 생성한 Member 객체 저장
        em.persist(member);
        // 7. 트랜잭션 커밋
        tx.commit();
        // 8. EntityManagerFactory 및 EntityManager 종료
        em.close();
        emf.close();
    }
}
주의
- 엔티티 매니저 팩토리는 하나만 생성해서 애플리케이션 전체에서 공유
- 엔티티 매니저는 쓰레드간에 공유하면 안된다.(사용하고 버려야한다.) 데이터베이스 커넥션 상 묶여버리는데, 공유하게 되면 다른 커넥션이 문제가 될 수도 있다 그러나 Spring을 사용하면 알아서 관리 해주기 때문에 크게 문제가 되지 않는다.
- JPA의 모든 데이터 변경은 트랜잭션에서 처리해야한다.