02. JPA 시작
01. Hello JPA - 프로젝트 생성
1. H2 데이터베이스 설치와 실행
2. 메이븐 소개
3. 프로젝트 생성
4. 라이브러리 추가 pom.xml
5. JPA 설정하기 - persistence.xml
6. 데이터베이스 방언
- JPA는 특정 데이터베이스에 종속 X
- 각각의 데이터베이스가 제공하는 SQL 문법과 함수는 조금씩 다름
- 방언: SQL 표준을 따르지 않는 각 DB만의 고유한 기능
	- ex) MySQL, Oracle SQL, H2 SQL
- hibernate.dialect 속성에 지정 (각각의 DB특성에 매핑되어 있음)
02. Hello JPA - 애플리케이션 개발
1. JPA 구동 방식
- Persistence Class에서 META-INF/persistence.xml 설정 정보를 읽음.
 
- EntityManagerFactory Class 생성
 
- 필요할때마다 EntityManagerFactory에서 EntityManger 생성
 
2. JPA 동작 확인
- JpaMain 클래스 생성
객체와 테이블을 생성하고 매핑하기
- @Entity: JPA가 관리할 객체
- @Id: DB PK와 매핑 
create table Member( 
    id bigint not null,
    name varchar(255),
    primary key (id)
);
package hellojpa;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Member {
    @Id
    private Long id;
    private String name;
    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;
    }
}
EntityManagerFactory 애플리케이션 로딩 시점에 딱 하나만 만들어야 함. 실제 DB에 저장하는 트랜잭션 단위 DB 커넥션을 얻어서 쿼리를 날려서 종료되는 일관적인 작업을 할때마다 EntityManager를 생성해야 함.
package hellojpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        //code
        Member member = new Member();
        em.persist(member); // 저장
        em.close();
        emf.close();
    }
}
error: ids for this class must be manually assigned
package hellojpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        //code
        Member member = new Member();
        member.setId(1L);
        member.setName("HelloA");
        em.persist(member); // 저장
        em.close();
        emf.close();
    }
}
JPA에서 트랜잭션 단위가 정말 중요함.
모든 데이터를 변경하는 모든 작업은 트랜잭션 안에서 작업을 해야함
public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        //code
        EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻을 수 있음
        tx.begin(); // DB 트랜잭션 시작
        Member member = new Member();
        member.setId(1L);
        member.setName("HelloA");
        em.persist(member); // 저장
        tx.commit(); // DB 커밋
        em.close();
        emf.close();
    }
}
package hellojpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        //code
        EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻을 수 있음
        tx.begin(); // DB 트랜잭션 시작
        Member member = new Member();
        member.setId(1L);
        member.setName("HelloA");
        em.persist(member); // 저장
        tx.commit(); // DB 커밋
        em.close();
        emf.close();
    }
}
정상적으로 SQL 쿼리문이 실행되는 것을 확인할 수 있음.
Hibernate: 
    /* insert hellojpa.Member
        */ insert 
        into
            Member
            (name, id) 
        values
            (?, ?)
실제 DB에서 쿼리문을 날려서 실행을 해보면 정상적으로 저장이 된 것을 확인 할 수 있음
값을 하나 더 넣어주면 저장이 잘 되는 것을 확인 가능
        member.setId(2L);
        member.setName("HelloB");
쿼리를 만든 적이 없고 JPA가 매핑 정보를 보고 알아서 넣어줌
정석 코드 
public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        //code
        EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻을 수 있음
        tx.begin(); // DB 트랜잭션 시작
        try {
            Member member = new Member();
            member.setId(2L);
            member.setName("HelloB");
            em.persist(member); // 저장
            tx.commit(); // DB 커밋
        } catch (Exception e) {
            tx.rollback();
        }finally {
            em.close();
        }
        emf.close();
    }
}
- 조회
 
package hellojpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        //code
        EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻을 수 있음
        tx.begin(); // DB 트랜잭션 시작
        try {
            Member findMember = em.find(Member.class, 1L);
            System.out.println("findMember.id = " + findMember.getId());
            System.out.println("findMember.name = " + findMember.getName());
            tx.commit(); // DB 커밋
        } catch (Exception e) {
            tx.rollback();
        }finally {
            em.close();
        }
        emf.close();
    }
}
실행을 하면 다음과 같이 쿼리문이 나오는 걸 확인할 수 있음.
Hibernate: 
    select
        member0_.id as id1_0_0_,
        member0_.name as name2_0_0_ 
    from
        Member member0_ 
    where
        member0_.id=?
findMember.id = 1
findMember.name = HelloA
- 삭제
em.remove(); - 수정
 
public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        //code
        EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻을 수 있음
        tx.begin(); // DB 트랜잭션 시작
        try {
            Member findMember = em.find(Member.class, 1L);
            findMember.setName("HelloJPA");
            
            tx.commit(); // DB 커밋
        } catch (Exception e) {
            tx.rollback();
        }finally {
            em.close();
        }
        emf.close();
    }
}
실행 결과: Update 쿼리문이 실행 되는 걸 확인할 수 있음.
Hibernate: 
    select
        member0_.id as id1_0_0_,
        member0_.name as name2_0_0_ 
    from
        Member member0_ 
    where
        member0_.id=?
Hibernate: 
    /* update
        hellojpa.Member */ update
            Member 
        set
            name=? 
        where
            id=?
실제 DB에서 조회를 해보면 값이 변경된 것을 확인할 수 있음.
why? 
- JPA를 통해서 Entity를 가져오면 JPA가 관리를 함.
 - JPA가 변경이 되었는지 트랜잭션을 commit하는 시점에서 체크를 함.
 - 바뀌었으면 트랜잭션 commit 하기 직전에 Update 쿼리를 만들어 날리고 트랜잭션이 커밋됨.
 
주의
- EntityManagerFactory는 웹서버가 올라오는 시점에서 DB당 하나가 생성이 됨
 - EntityManger라는 것은 고객의 요청이 올때마다 계속 사용했다가 버렸다가 동작
조심해야 할 부분: 쓰레드간에 절대 공유해서는 안됨 - 장애가 발생(사용하고 버려야 한다.) - JPA의 모든 데이터 변경은 트랜잭션 안에서 실행
 - 내부적으로 DB가 트랜잭션 쿼리를 다 처리
 
JPQL 소개
- 가장 단순한 조회 방법
- EntityManager.find()
- 객체 그래프 탐색(a.getB().getC()) - 나이가 18살 이상인 회원을 모두 검색하고 싶다면?
 
public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        //code
        EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻을 수 있음
        tx.begin(); // DB 트랜잭션 시작
        try {
//            Member findMember = em.find(Member.class, 1L);
//            findMember.setName("HelloJPA");
            List<Member> result = em.createQuery("select m from Member as m", Member.class)
                    .getResultList();
            for (Member member : result) {
                System.out.println("member.names = " + member.getName());
            }
            tx.commit(); // DB 커밋
        } catch (Exception e) {
            tx.rollback();
        }finally {
            em.close();
        }
        emf.close();
    }
}
아래와 같은 결과값이 나오는 것을 확인할 수 있다.
Hibernate: 
    /* select
        m 
    from
        Member as m */ select
            member0_.id as id1_0_,
            member0_.name as name2_0_ 
        from
            Member member0_
member.names = HelloJPA
member.names = HelloB
이거의 장점이 뭐지?
public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        //code
        EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻을 수 있음
        tx.begin(); // DB 트랜잭션 시작
        try {
//            Member findMember = em.find(Member.class, 1L);
//            findMember.setName("HelloJPA");
            List<Member> result = em.createQuery("select m from Member as m", Member.class)
                    .setFirstResult(5)
                    .setMaxResults(10)
                    .getResultList();
            for (Member member : result) {
                System.out.println("member.names = " + member.getName());
            }
            tx.commit(); // DB 커밋
        } catch (Exception e) {
            tx.rollback();
        }finally {
            em.close();
        }
        emf.close();
    }
}
JPQL: 객체를 대상으로 하는 객체지향 쿼리이기 때문에 DB의 방언에 맞게 매핑을 해서 쿼리문을 날려줌.
package hellojpa;
public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        //code
        EntityTransaction tx = em.getTransaction(); // 트랜잭션 얻을 수 있음
        tx.begin(); // DB 트랜잭션 시작
        try {
//            Member findMember = em.find(Member.class, 1L);
//            findMember.setName("HelloJPA");
            List<Member> result = em.createQuery("select m from Member as m", Member.class)
                    .setFirstResult(5)
                    .setMaxResults(10)
                    .getResultList();
            for (Member member : result) {
                System.out.println("member.names = " + member.getName());
            }
            tx.commit(); // DB 커밋
        } catch (Exception e) {
            tx.rollback();
        }finally {
            em.close();
        }
        emf.close();
    }
}
실습 - JPQL 소개
• JPQL로 전체 회원 검색
• JPQL로 ID가 2 이상인 회원만 검색
• JPQL로 이름이 같은 회원만 검색
• JPQL에 대해 자세한 내용은 객체지향 쿼리에서 학습
  
JPA를 사용하면 엔티티 객체를 중심으로 개발
• 문제는 검색 쿼리
• 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색
  (why? 테이블을 가져오면 JPA의 사상이 깨지니까)
• 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능
• 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검
색 조건이 포함된 SQL이 필요(실제 RDB에 있는 물리적인 DB에 쿼리를 날리면 그 DB에 종속적으로 설계가 되기 때문에 엔티티 객체를 대상으로 하는 쿼리를 날리는 JPQL 사용)
  
JPQL
• JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어 제공
• SQL과 문법 유사, SELECT, FROM, WHERE, GROUP BY,
HAVING, JOIN 지원
• JPQL은 엔티티 객체를 대상으로 쿼리
• SQL은 데이터베이스 테이블을 대상으로 쿼리
테이블이 아닌 객체를 대상으로 검색하는 객체 지향 쿼리
• SQL을 추상화해서 특정 데이터베이스 SQL에 의존X
• JPQL을 한마디로 정의하면 객체 지향 SQL
• JPQL은 뒤에서 아주 자세히 다룸
- Jpa 동작 확인
                Author And Source
이 문제에 관하여(02. JPA 시작), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@raesong/02.-JPA-시작저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)