정리노트/JPA

자바 ORM 표준 JPA 프로그래밍 - 기본편 03

컵라면만두세트 2022. 4. 26. 20:34

JPQL

JPA를 활용하여 엔티티 객체를 중심으로 개발 한다.

검색하는 작업을 효율적으로 진행하기 위에 JPA는 JPQL 이라는 쿼리 언어로 SQL을 실행하도록 지원해준다.

em.createQuery("JQL쿼리", JPQL에 사용되는 클래스타입);

예제

List<Member> result = em.createQuery("select  m from Member as m", Member.class)
                    .setFirstResult(5)
                    .setMaxResults(8)
                    .getResultList();

JPQL이라는 객체지향 쿼리 언어를 제공

SQL 데이터베이스 테이블 대상으로 쿼리를 제공한다.

select m from Member as m SQL과 다르게 실제 엔티티가 from의 대상이 된다.

 

영속성 관리

JPA가 제공하는 기능

EntitiyMangerFactory 와 EntityManger

EntityMangerFactory

  • 보통 데이터베이스 1개만 사용하는 애플리케이션은 일반적으로 EntityMangerFactory하나만 생성

EntityMangerFactory 생성방법

 EntityManager em = emf.createEntityManager();
  • 이름과 비슷하게 비용이 상당하다 때문에 1개만 만들어서 애플리케이션 전체에서 공유하도록 설계 해줘야 한다.

XML 방식) META-INF/persistence.xml

    <persistence version="2.2"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
    <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="1234"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/practiceJPA"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle12cDialect"/>

            <!-- 옵션 -->
            <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.hbm2ddl.auto" value="create" />-->
        </properties>
    </persistence-unit>
</persistence>

  • Persistence.createEntityManagerFactory("hello"); 를 호출하면 META-INF / persistence.xml에서 <persistence-unit name="hello"> 이라는 정보를 바탕으로 EntityManagerFactory를 생성한다.

엔티티 매니저

엔티티를 수정하고, 삭제, 조회 등 엔티티와 관련된 모든 일을 처리한다. 엔티티를 저장하는 가상의 데이터 베이스라고 생각해보자.

 EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
 EntityManager em = emf.createEntityManager();

영속성 컨텍스트

  • 엔티티를 영구 저장하는 환경
  • 캐시와 같은 역할을 수행, 내부적으로 엔티티 보관
  • EntityManger를 사용하면 영속성 켄텍스트에 엔티티 저장 및 조회
em.persist(member);

EntityManger 는 엔티티를 영속성 컨텍스트에 보관하고 관리

이후 commit이 일어나면 영속성 컨텍스트에서 쿼리 만들어 DB에 반영

비영속 : 영속성 컨텍스트와 전혀 관계가 없는상태

영속 : 영속성 컨텍스트에 저장된 상태

public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();

        // 트랜잭션을 생성하고 시작하고
        // commit 까지 하면 실행 됨
        tx.begin();

        //  객체.setName set을 활용하면 update
        try{
            //비영속 : 엔티티를 생성한 상태 
            Member member = new Member();
            member.setId(100L);
            member.setName("HelloJPA");

            //영속
            System.out.println("--BEFORE--");
						//객체를 저장한 상태
            em.persist(member);
            System.out.println("--AFTER--");

						//commit을 해야 DB에 저장이 된상태
            tx.commit();
        }catch(Exception e){

            tx.rollback();
        }finally {

            em.close();
        }

        emf.close();
    }

}

1차 캐시에서 조회

try{
            //비영속
            Member member = new Member();
            member.setId(101L);
            member.setName("HelloJPA");

            //영속
            System.out.println("--BEFORE--");
            em.persist(member);
            System.out.println("--AFTER--");

            Member findMember = em.find(Member.class, 101L);
            System.out.println("findMember.id = " + findMember.getId());
            System.out.println("findMember.name = " + findMember.getName());

            tx.commit();
        }

데이터베이스에서 조회

  • 영속 엔티티 동일성 보장
//영속
            Member findMember1 = em.find(Member.class, 101L);
            Member findMember2 = em.find(Member.class, 101L);

						System.out.println("result == " + (findMember2 == findMember1));

            tx.commit();
  • 엔티티 등록
public class JpaMain {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();

        // 엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야한다.
        tx.begin();
        
        try{
            //영속
            Member member1 = new Member(150L, "A");
            Member member2 = new Member(160L,"B");

            em.persist(member1);
            em.persist(member2);

            System.out.println("--------------");
            // commit 하는 순간 데이터베이스에 insert sql을 보낸다

            tx.commit();
        }catch(Exception e){

            tx.rollback();
        }finally {

            em.close();
        }

        emf.close();
    }

}
  • 엔티티 수정
try{
            //영속
            Member member = em.find(Member.class, 150L);
            member.setName("ZZZZ");

            em.persist(member);

            System.out.println("--------------");
            // commit 하는 순간 데이터베이스에 insert sql을 보낸다

            tx.commit();
        }
  • 엔티티 삭제

플러시

영속성 컨텍스트의 변경내용을 DB에 반영

  • FlushModeType.AUTO : 커밋이나 쿼리를 실행할 때 플러시(기본값)
  • FlushModeType.COMMIT : 커밋할 때만 플러시

플러시라는 이름으로 인해 영속성 컨텍스트에 보관된 엔티티를 지운다고 생각 하면 안됨

트랜잭션 커밋 직전에만 변경 내용을 데이터베이스에 보내 동기화하면 된다

준영속 상태 특징

  • 거의 비영속 상태에 가깝다
  • 식별자 값을 가지고 있다 , 한 번 영속 상태를 갔다 왔기 때문에 ID값이 있다.
  • 지연 로딩을 할 수 없다

병합

준영속 상태의 엔티티를 어떻게 다시 영속 상태로 만들까?

merge()메소드는 준영속 상태의 엔티티를 받아 새로운 영속 상태의 엔티티를 반환

최종

  • 엔티티 매니저는 엔티티 매니저 팩토리에서 생성
  • 영속성 컨텍스트는 엔티티 매니저를 통해 접근이 가능하고, 객체를 보관하는 가상의 데이터 베이스 역할을 한다.
  • 영속성 컨텍스트에 저장한 엔티티는 플러시 시점에 데이터 베이스에 반영되고, 일반적으로 트랜잭션 커밋을 할때 영속성 컨텍스트가 플러시가 된다.
  • 영속성 컨테스트가 관리하는 엔티티를 더 이상 관리하지 못하면, 준영속 상태의 엔티티라 부른다. 때문에 영속성 컨텍스트가 제공하는 기능들을 활용할 수 없다. (1차 쓰기 지연, 변경감지, 지연 로딩 등)