JPA

kmb·2022년 7월 27일
0

JPA

목록 보기
1/7
post-thumbnail

JPA (Java Persistence API)

자바 진영의 ORM 기술 표준.
즉, 어떻게 기능과 속성을 한곳에 관리할지를 지향하는 Java와 어떻게 데이터를 저장할지를 지향하는 RDBMS 사이에서
2개의 영역을 중간에서 패러다임을 일치 시키기위한 스펙이라고 이해하면 된다.

ORM (Object Realtional Mapping) : 객체 관계 매핑으로써 객체는 객체대로 설계하고, RDBMS는 RDBMS대로 설계하는데 ORM 프레임워크가 중간에서 매핑을 해준다.

JPA는 단순 스펙이기 때문에 해당 스펙을 구현하는 구현체마다 회사이름이나 프레임워크 이름이 다르다.
ORM을 지원하는 유명한 프레임워크중에는 Hibernate 오픈소스가 있다. (JPA와 Hibernate의 관계를 인터페이스 - 클래스 관계처럼 이해하면 될듯하다)

Spring Data JPA : Spring에서 JPA를 쉽게 사용할 수 있도록 제공하는 모듈.
기존의 JPA에서는 EntityManager를 주입받아야 했다면
Spring Data JPA는 JpaRepository 인터페이스를 상속받아서 내부적으로 정해진 메서드를 사용하면 Spring이 목적에 맞는 적합한 쿼리를 날리는 구현체를 만들어서 Spring Bean으로 등록한다.


JPA 작동 방식

  • EntityManagerFactory 는 웹서버가 올라오는 시점에 DB당 1개만 생성되며, 애플리케이션 전체에서 공유.
  • EntityManager 는 클라이언트의 요청이 올때마다 생성된다.
    ( 쓰레드간에 절대로 공유가 되면 안된다 )
  • JPA의 모든 데이터 변경은 Transaction 안에서 실행되어야 한다.

영속성 컨텍스트(Persistence Context)

엔티티를 영구 저장하는 환경.
EntityManager를 통해서 영속성 컨텍스트에 접근한다.

 

  • 엔티티 생명주기
  1. 비영속(new/transient) : 영속성 컨텍스트와 전혀 관계가 없는 상태
// 비영속 상태
Member member = new Member();
member.setId(1L);
member.setName("Test1");
  1. 영속(managed) : 영속성 컨텍스트에 관리되는 상태
// 비영속 상태
Member member = new Member();
member.setId(1L);
member.setName("Test1");

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

// 영속 상태
em.persist(member);
  1. 준영속(detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태
em.detach(member);
  1. 삭제(removed) : 삭제된 상태
em.remove(member);

JPA 내부 동작 코드 (생성)

public static void main(String[] args) {

	EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

	EntityManager em = emf.createEntityManager();

	EntityTransaction tx = em.getTransaction();
	tx.begin();

	try {
		Member member = new Member();
		member.setId(1L);
		member.setName("Test1");

		em.persist(member);

		tx.commit();

	} catch (Exception e) {

		tx.rollback();

	} finally {

		em.close();
	}
	emf.close();
}
  1. EntityManagerFactory에서 EntityManager를 생성.

  2. EntityManagerTransaction을 실행.

  3. 엔티티에 사용자가 입력한 값을 .persist( ) 메서드를 이용하여 영속성 컨텍스트 안에 넣는다.

  4. Transaction commit을 하면 DB에 반영이 된다.
    만약 commit이 되기전에 중간에 문제가 생기면 rollback된다.

  5. 이후 EntityManager가 종료되고 마지막으로 EntityManagerFactory가 종료된다.

    H2 DB내의 MEMBER 테이블에 id=1, name="Test1" 값이 insert 되었음을 확인 할 수 있다.


JPA 내부 동작 코드 (조회)

public static void main(String[] args) {

	EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

	EntityManager em = emf.createEntityManager();

	EntityTransaction tx = em.getTransaction();
	tx.begin();

	try {
    
		Member findMember = em.find(Member.class, 1L);

	} catch (Exception e) {

		tx.rollback();

	} finally {

		em.close();
	}
	emf.close();
}

EntityManager의 .find( ) 메서드를 사용하면 select 쿼리문으로 데이터를 조회한다.


JPA 내부 동작 코드 (변경)

public static void main(String[] args) {

	EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

	EntityManager em = emf.createEntityManager();

	EntityTransaction tx = em.getTransaction();
	tx.begin();

	try {
    
		Member findMember = em.find(Member.class, 1L);
        findMember.setName("Test2");
        
        tx.commit();

	} catch (Exception e) {

		tx.rollback();

	} finally {

		em.close();
	}
	emf.close();
}

영속성 컨텍스트에 있는 데이터는 JPA가 관리하는데
transaction commit 하기 직전에 변경되었는지 확인을 한다.
만약 변경되었다면 update 쿼리를 날린다음 commit을 한다.

H2 DB내의 MEMBER 테이블에 id=1, name="Test1" 값이
id=1, name="Test2" 로 변경되었음을 확인할 수 있다.


JPA 내부 동작 코드 (삭제)

public static void main(String[] args) {

	EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

	EntityManager em = emf.createEntityManager();

	EntityTransaction tx = em.getTransaction();
	tx.begin();

	try {
    
		Member findMember = em.find(Member.class, 1L);

		em.remove(findMember);

		tx.commit();

	} catch (Exception e) {

		tx.rollback();

	} finally {

		em.close();
	}
	emf.close();
}

EntityManager의 .remove( ) 메서드를 사용하면 delete 쿼리문으로 데이터를 삭제한다.


객체 지향 쿼리 언어 (JPQL, Java Persistence Query Language)

JPA는 DB 테이블을 대상으로 쿼리를 만들지 않고, 엔티티 객체를 중심으로 쿼리를 만든다.
하지만 검색 쿼리의 경우 모든 DB 데이터를 객체로 변환해서 검색하는것이 불가능하다.
따라서 JPA는 SQL을 추상화한 객체 지향 쿼리 언어(JPQL)를 제공한다.

  • JPQL 특징
  1. SQL 문법과 유사한 SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN을 사용할 수 있다.
  2. 엔티티 객체를 대상으로 SQL을 추상화해서 검색하는 객체지향쿼리 이므로 특정 DB SQL에 의존하지 않는다.

JPQL 예시

public static void main(String[] args) {

	EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

	EntityManager em = emf.createEntityManager();

	EntityTransaction tx = em.getTransaction();
	tx.begin();

	try {
    
		List<Member> result = em.createQuery("select m from Member as m", Member.class)
                    .getResultList();

        for(Member member : result) {
			System.out.println("member.name = " + member.getName());
		}

	} catch (Exception e) {

		tx.rollback();

	} finally {

		em.close();
	}
	emf.close();
}

JPQL 쿼리를 작성할때는 엔티티 객체로 임의로 지정한 m을 사용했지만, 실제 동작한 쿼리를 보면 모든 필드가 나열 되어있는것을 볼 수 있다.

 

출처

profile
꾸준하게

0개의 댓글