JPA

[JPA] 개념 정리, 간단한 개념 정리 - 1일차

songsua 2025. 1. 31. 16:58

 

기본 정리 및 설정 

사용해야하는 이유
1. SQL 중심적인 개발에서 객체 중심으로 개발

2. 생상선: CRUD(저장, 조회, 수정, 삭제)

3. 유지보수: 기존에는 필드 변경 시 모든 SQL을 변경해야 했다. 이제는 JPA rk gownsek

4. 패러다임의 불일치 해결 : 상속(jpa.persist), 조회(jpa.find), 연관관계

5. 데이터 접근 추상화와 벤더 독립성

6. 1차 캐시와 동일성 보장 : 같은 트랜잭션 안에서는 같은 엔티티를 반환, 트랜잭션을 커밋할 때까지 insert SQL을 모음
7. 지연 로딩과 즉시 로딩 : 성능 최적화를 위해 select * from 할 때 필요한 애들만 조회하게 만들었다.

  • 지연로딩 : 객체가 실제 사용될 때 로딩 
  • 즉시로딩 : JOIN SQL로 한번에 연관된 객체까지 미리 조회

 

persistence.xml 설정

<?xml version="1.0" encoding="UTF-8"?>
<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=""/>
            <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"/>
            <!--<property name="hibernate.hbm2ddl.auto" value="create" />-->
        </properties>
    </persistence-unit>

</persistence>

 

위에 보면. javax 랑 hibernate  등이 있는데, javax 다른 jpa 구현 라이브러리를 사용해도 가능하다

반면, hibernate는 다른 라이버리를 쓸 경우에는 바꿔줘야한다. 전용 옵션이라고 이해하면 될 것같다.

 

애플리케이션 개발

1. 객체와 테이블을 생성하고 매핑하기 

package hellojpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class JpaMain {
    public static void main(String[] args) {
        //Persistence-unit에 적은 name 을 적야야한다.
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager entityManager = emf.createEntityManager();
        //code를 작성하기 시작할 것이다.
        //종료하기
        entityManager.close();
        emf.close();
        
    }
}

 

 

@Entity : JPA 가 관리할 객체

@Id : 데이터베이스 PK와 매핑

 

- 실습

1. Table 만들어보기


JPQL이란? 
JPA에서 엔티티 객체를 대상으로 쿼리를 실행하는 언어이다.
SQL과 문법이 비슷하지만, 테이블이 아닌 엔티티 객체를 기준으로 쿼리를 작성

전체회원검색 : 

package hellojpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;

public class JpaMain {
    public static void main(String[] args) {
        //Persistence-unit에 적은 name 을 적야야한다.
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        //code를 작성하기 시작할 것이다.
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        try {
            List<Member> result = em.createQuery("select m from Member", Member.class).getResultList();
           
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
        //종료하기
        emf.close();

    }
}
  • EntityManagerFactory : JPA는 항상 해당 명령어로 만들어놔야한다. 데이터베이스가 하나씩 묶여서 돌아가는 것
  • EntityManager : 고객이 요청이 올때마다 해당 매니저를 통해 실핼 해야 한다
  • EntityTrasaction :모든 데이터 변경은 트랜잭션을 통해서 일어난다.
  • close() : 자원을 다 사용했을 경우에는 꼭 닫아줘야한다.

 

JPA에서 가장 중요한 2가지

1. 객체와 관계형 데이터베이스 매핑하는 것

2. 영속성 컨텍스트: 엔티티를 영구 저장하는 환경

  • 엔티티 매니저 팩토리 : 해당 부분은 고객이 요청이 올 때마다 엔티티 매니저를 생성한다.
  • 엔티티 매니저 : 내부적으로 데이터베이스 커낵션을 통해 데이터베이스를 사용한다.

디비에 쿼리가 들어가는 순간은 언제 일까?

 

영속성 컨텍스트가 필요한 이유

  1. 1차캐시
  2. 동일성 보장
  3. 트랜잭션을 지원하는 쓰기 지연
  4. 변경 감지
  5. 지연 로딩

1. 엔티티 조회, 1차 캐시

//엔티티를 생성한 상태(비영속)
//단순하게 생성만한 상태를 비영속 이라고 한다
Member member = new Member();
member.setId("member1");
member.SetUsername("회원1");

//엔티티를 영속
em.persist(member);

em.persist 단계에서도 데이터베이스에 저장된 상태가 아니인데,
find 명령어로 찾기 시작할 때, 데이터베이스에서 먼저 찾지 않고 영속 컨텍스트(Entity Manager) 에서 먼저 찾기 시작한다.

이를 "1차 캐시" 이다. 

 

1차 캐시에 없을 경우에는

데이터베이스에서 가져와서 영속 컨텍스트에 저장한다.

 

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋

Insert SQL해도 데이터베이스에 안보내고, commit 해야지 데이터베이스에 보낸다.

flush() : 영속성 컨텍스트의 변경대용을 데이터베이스에 반영

  • 변경 감지
  • 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
  • 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송

영속성 컨텍스트를 플러시하는 방법

1. em.flush() : 직접 호출

2. 트랜잭션 커밋 : 플러시 자동 호출

3. JPQL 쿼리 실행 : 플러시 자동 호출

flush 한다고 1차캐시는 삭제되지 않는다. 그저 데이터베이스에 반영되는 것이라고 생각하면 된다.