본문 바로가기

JPA

[JPA] JPA 동작 확인

목차

  • JPA 구동 방식
  • JPA 동작 확인(CRUD)
  • JPA 주의점
  • JPQL 소개

 

JPA 구동 방식

  1. Persistence 클래스에서 시작
  2. persistence.xml 에서 설정 정보를 읽고 EntityManagerFactory 생성
  3. 필요할 때마다 EntityManager 찍어서 돌리면 됨.

 

 

JPA 동작 확인

  • JpaMain 클래스 생성
  • JPA 동작 확인

 

JpaMain 

public class JpaMain {

    public static void main(String[] args) {
        // persistence.xml의 Unit Name 넘기기
        // <persistence-unit name="hello">
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        // EntityManagerFactory에서 EntityManager 꺼내기
        EntityManager em = emf.createEntityManager();

        //실제 동작하는 코드 작성(DB 저장, 조회 같은)
        
        // EntityManager 종료
        em.close();
        // EntityManagerFactory 종료
        emf.close();
    }
}

 

 

 

테이블을 생성

create table Member ( 
    id bigint not null, 
    name varchar(255), 
    primary key (id) 
);

 

 

객체 생성 후 테이블과 매핑하기

package hellojpa;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;

@Entity // JPA가 관리해야 하는 대상 인식
public class Member {
    
    @Id // PK 알려주기
    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;
    }
}
  • @Entity: JPA가 관리할 객체
  • @Id: 데이터베이스 PK와 매핑

 

 

회원 추가 (오류)

package hellojpa;

import jakarta.persistence.*;

public class JpaMain {

    public static void main(String[] args) {
        // persistence.xml의 Unit Name 넘기기
        // <persistence-unit name="hello">
        // application 로딩 시점에 딱 하나를 만들어야 함
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        
        // EntityManagerFactory에서 EntityManager 꺼내기
        // DB 커넥션을 얻어서 쿼리를 날리고 종료되는 어떠한 일관적인 단위를 할 때마다 엔티티 매니저를 꼭 만들어줘야 함
        EntityManager em = emf.createEntityManager();

        //실제 동작하는 코드 작성(DB 저장, 조회 같은)
        Member member = new Member();
        member.setId(1L); // PK는 NOT NULL
        member.setName("HelloA");
        em.persist(member); // Member 저장
        
        // EntityManager 종료
        em.close();
        // EntityManagerFactory 종료
        emf.close();
    }
}
  • 정상적으로 동작할 것 같지만 오류가 발생한다.
  • JPA에서 모든 데이터를 변경하는 작업은 꼭 transaction 안에서 작업해야 한다.

 

 

회원 추가 코드 수정

package hellojpa;

import jakarta.persistence.*;

public class JpaMain {

    public static void main(String[] args) {
        // persistence.xml의 Unit Name 넘기기
        // <persistence-unit name="hello">
        // application 로딩 시점에 딱 하나를 만들어야 함
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        
        // EntityManagerFactory에서 EntityManager 꺼내기
        // DB 커넥션을 얻어서 쿼리를 날리고 종료되는 어떠한 일관적인 단위를 할 때마다 엔티티 매니저를 꼭 만들어줘야 함
        EntityManager em = emf.createEntityManager();
        
        // 1, 트랜잭션 얻기
        EntityTransaction tx = em.getTransaction();
        
        // 2. 트랙잭션 시작
        tx.begin();

        //실제 동작하는 코드 작성(DB 저장, 조회 같은)
        Member member = new Member();
        member.setId(1L); // PK는 NOT NULL
        member.setName("HelloA");
        em.persist(member); // Member 저장
        
        // 3. 커밋
        tx.commit();
        
        // EntityManager 종료
        em.close();
        // EntityManagerFactory 종료
        emf.close();
    }
}

 

 

참고: JPA 설정 정보

<!-- 옵션 -->
<property name="hibernate.show_sql" value="true"/> // SQL 문 보여줌
<property name="hibernate.format_sql" value="true"/> // SQL 문 이쁘게
<property name="hibernate.use_sql_comments"  value="true"/> // 쿼리가 어디서 나왔는지(주석 부분)
<property name="hibernate.hbm2ddl.auto" value="create" />

 

 

DB 확인

 

  • 하지만 Member 객체가 Member 테이블에 저장하라고 한 적이 없다.
  • 이것은 관례를 따른 것이다.

 

참고: 테이블명과 컬럼명이 다르다면

@Entity 
@Table(name = "USER") // user 라는 테이블에 쿼리 날림
public class Member {
@Entity // JPA가 관리해야 하는 대상 인식
    
    @Id // PK 알려주기
    private Long id;
    
    Column(name = "username") // 테이블과 컬럼이름과 매핑
    private String name;
    }

 

 

 

회원 수정

package hellojpa;

import jakarta.persistence.*;

public class JpaMain {

    public static void main(String[] args) {
        // persistence.xml의 Unit Name 넘기기
        // <persistence-unit name="hello">
        // application 로딩 시점에 딱 하나를 만들어야 함
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        
        // EntityManagerFactory에서 EntityManager 꺼내기
        // DB 커넥션을 얻어서 쿼리를 날리고 종료되는 어떠한 일관적인 단위를 할 때마다 엔티티 매니저를 꼭 만들어줘야 함
        EntityManager em = emf.createEntityManager();
        
        // 1, 트랜잭션 얻기
        EntityTransaction tx = em.getTransaction();
        
        // 2. 트랙잭션 시작
        tx.begin();

        //실제 동작하는 코드 작성(DB 저장, 조회 같은)
        try {
            Member findMember = em.find(Member.class, 1L);// 클래스와 PK값 파라미터 전달
            System.out.println("findMember.id = " + findMember.getId());
            System.out.println("findMember.name = " + findMember.getName());
            // 회원 이름 변경
            findMember.setName("쌈뽕");
            
            // em.persist(findMember); // Member 저장 안해도 됨!!!!

            // 3. 커밋
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            // EntityManager 종료
            em.close();
            // EntityManagerFactory 종료
            emf.close();
        }
    }
}

  • JPA 가 뭔가 바뀌었다고 인지하면 트랜잭션 커밋하기 직전에 업데이트 쿼리를 날리고 커밋이 된다.
  • 어마어마한 장점

 

 

회원 삭제

package hellojpa;

import jakarta.persistence.*;

public class JpaMain {

    public static void main(String[] args) {
        // persistence.xml의 Unit Name 넘기기
        // <persistence-unit name="hello">
        // application 로딩 시점(웹 서버에 올라오는 시점)에 DB당 딱 하나를 만들어야 함
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        
        // EntityManagerFactory에서 EntityManager 꺼내기
        // DB 커넥션을 얻어서 쿼리를 날리고 종료되는 어떠한 일관적인 단위를 할 때마다 엔티티 매니저를 꼭 만들어줘야 함
        EntityManager em = emf.createEntityManager();
        
        // 1, 트랜잭션 얻기
        EntityTransaction tx = em.getTransaction();
        
        // 2. 트랙잭션 시작
        tx.begin();

        //실제 동작하는 코드 작성(DB 저장, 조회 같은)
        try {
            Member findMember = em.find(Member.class, 1L);// 클래스와 PK값 파라미터 전달
            
            em.remove(findMember); // 회원 삭제

            // 3. 커밋
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            // EntityManager 종료
            em.close();
            // EntityManagerFactory 종료
            emf.close();
        }
    }
}

 

 

 

 

회원 단건 조회

package hellojpa;

import jakarta.persistence.*;

public class JpaMain {

    public static void main(String[] args) {
        // persistence.xml의 Unit Name 넘기기
        // <persistence-unit name="hello">
        // application 로딩 시점에 딱 하나를 만들어야 함
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        
        // EntityManagerFactory에서 EntityManager 꺼내기
        // DB 커넥션을 얻어서 쿼리를 날리고 종료되는 어떠한 일관적인 단위를 할 때마다 엔티티 매니저를 꼭 만들어줘야 함
        EntityManager em = emf.createEntityManager();
        
        // 1, 트랜잭션 얻기
        EntityTransaction tx = em.getTransaction();
        
        // 2. 트랙잭션 시작
        tx.begin();

        //실제 동작하는 코드 작성(DB 저장, 조회 같은)
        try {
            Member findMember = em.find(Member.class, 2L);// 클래스와 PK값 파라미터 전달
            System.out.println("findMember.getId() = " + findMember.getId());
            System.out.println("findMember.getName() = " + findMember.getName());
            
            // 3. 커밋
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            // EntityManager 종료
            em.close();
            // EntityManagerFactory 종료
            emf.close();
        }
    }
}

findMember.getId() = 2
findMember.getName() = HelloB

 

 

주의점

  • 엔티티 매니저 팩토리는 하나만 생성해서 애플리케이션 전체에서 공유
  • 엔티티 매니저는 쓰레드간에 공유X (사용하고 버려야 한다). 
  • JPA의 모든 데이터 변경은 트랜잭션 안에서 실행

 

 

 

JPQL 소개

  • 가장 단순한 조회 방법
    • EntityManager.find() 
    • 객체 그래프 탐색(a.getB().getC()) 
  • 나이가 18살 이상인 회원을 모두 검색하고 싶다면? (1 ~8 번까지 페이징 처리)
List<Member> result =
em.createQuery("select m from Member m where m.id >= 2", Member.class)
        .setFirstResult(1)
        .setMaxResults(8)
        .getResultList();

 

 

JPA를 사용하면 엔티티 객체를 중심으로 개발

  • 문제는 검색 쿼리
  • 검색을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색
  • 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능
  • 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요

 

 

JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어 제공

  • SQL과 문법 유사, SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 지원
  • JPQL은 엔티티 객체를 대상으로 쿼리
  • SQL은 데이터베이스 테이블을 대상으로 쿼리

 

 

테이블이 아닌 객체를 대상으로 검색하는 객체 지향 쿼리

  • SQL을 추상화해서 특정 데이터베이스 SQL에 의존X 
  • JPQL을 한마디로 정의하면 객체 지향 SQL 

'JPA' 카테고리의 다른 글

[JPA] 엔티티 매핑  (0) 2024.06.24
[JPA] 영속성 컨텍스트  (0) 2024.06.24
[JPA] JPA란 뭘까?  (0) 2024.06.23
[JPA] 도메인 분석 설계  (0) 2024.06.20
[JPA] 프로젝트 환경 설정  (0) 2024.06.19