Spring Boot Data JPA

김정훈·2024년 7월 22일

Spring

목록 보기
18/24

JPA

0. ORM

객체 👈👉 번역(ORM) 👈👉 DB

1. JPA란?

JPA (Java Persistence API) : ORM 표준 (Object Relational Mapping), 자바 영속성 API
자바 애플리케이션에서 객체-관계 매핑(ORM)을 통해 관계형 데이터베이스의 데이터를 관리하고 조작하는 데 사용되는 표준 API입니다. JPA는 애플리케이션 개발자가 데이터베이스와 상호작용할 때 객체 지향적인 접근 방식을 사용하도록 도와줍니다.
Hibernate Entity Manager

자바 영속성 API

  • 영속성 : 상태 변화 감지 메모리
  • 데이터 값이 변경 : UPDATE 쿼리
  • 없는 데이터를 추가한 엔티티 : INSERT 쿼리
  • 데이터 제거 : DELETE 쿼리
  • 동일한 코드 👉 드라이버 변경 👉 플랫폼에 맞는 쿼리 실행

2. JPA 동작 방식

엔티티 : 엔티티 클래스의 정의 : 테이블의 정의, 각각의 엔티티는 데이터 하나 하나 👉 메모리에 적재
EntityManagerFactory : EntityManager 생성, 트랜잭션 생성 필수
EntityManager : 엔티티 영속성 관리

3. 영속성 컨택스트

1) find()

조회, 기본키로 조회, 이미 영속성에 엔티티가 있으면 DB에서 조회 ❌ - 1차 캐시, 성능상 이점

2) persist()

영속성 컨텍스트에 엔티티를 영속 : 상태 감지 시작

3) remove()

영속성 상태 -> 제거 상태 : DELETE

4) flush()

DB 반영
참고) find(..) 조회 메서드 호출시 flush()가 먼저 진행 되고 👉 조회

5) detach()

영속성 분리 : 상태감지 ❌

6) clear()

영속성 전체 제거

7) merge()

분리된 영속성 👉 영속 상태 : 상태 감지 ⭕️

@Data
@Entity //엔티티 에노테이션 설정하면 자동으로 테이블이 생성
public class Member {
    @Id
    private Long seq;
    private String email;
    private String password;
    private String userName;
    private LocalDateTime createdAt;
    private LocalDateTime modifiedAt;
}
@SpringBootTest
@TestPropertySource(properties = "spring.profiles.active=test")
public class Ex01 {

    @PersistenceContext //영속객체 의존성주입
    private EntityManager em;

    @Test
    void test1(){
        //EntityTransaction tx = em.getTransaction();
        //tx.begin(); //트랜잭션 시작

        Member member = new Member();
        member.setSeq(1L);
        member.setEmail("user01@test.org");
        member.setPassword("12345678");
        member.setUserName("사용자01");
        member.setCreatedAt(LocalDateTime.now());

        em.persist(member); //영속 상태 - 변화감지 메모리에 있다. 변화감지..
        em.flush(); //INSERT 쿼리

        member.setUserName("(수정)사용자01");
        member.setCreatedAt(LocalDateTime.now());
        em.flush(); //UPDATE 쿼리

        em.remove(member); //제거 상태, 제거 X, 상태만..
        em.flush(); //DELETE 쿼리

        //tx.commit();
    }
}

@SpringBootTest
@Transactional
@TestPropertySource(properties = "spring.profiles.active=test")
public class Ex01 {

    @PersistenceContext //영속객체 의존성주입
    private EntityManager em;

    @Test
    void test1(){
        Member member = new Member();
        member.setSeq(1L);
        member.setEmail("user01@test.org");
        member.setPassword("12345678");
        member.setUserName("사용자01");
        member.setCreatedAt(LocalDateTime.now());

        em.persist(member); //영속 상태 - 변화감지 메모리에 있다. 변화감지..
        em.flush(); //INSERT 쿼리
        em.detach(member); //영속상태분리 - 변화감지 X

        member.setUserName("(수정)사용자01");
        member.setCreatedAt(LocalDateTime.now());
        em.flush(); //UPDATE 쿼리
        em.merge(member);//분리된 영속 상태 -> 영상 상태(변화감지상태)
        em.flush();



    }
}

5. 영속성 컨텍스트 사용 시 이점

캐시역할

  • 영속성 컨택스트는 캐시 역할을 한다. 엔티티가 캐리에 존재한다면 SELECT 쿼리를 실행하지않고, 영속성상태에 있는 엔티티를 데이터베이스에서 조회하지않고 캐시에서 조회해서 꺼내온다.
  • clear()를 선택해서 영속 상태 엔티티 모두 비운다면, 캐시에 엔티티가 없기 때문에 DB에서 조회를 해서 가져오고, 캐시에 저장한다.

@SpringBootTest
@Transactional
@TestPropertySource(properties = "spring.profiles.active=test")
public class Ex02 {

    @PersistenceContext
    private EntityManager em;

    @BeforeEach
    void init(){
        for(long i = 1L; i <= 10L; i++){
            Member member = new Member();
            member.setSeq(i);
            member.setEmail("user " + i + "@test.org");
            member.setPassword("12345678");
            member.setUserName("사용자" + i);
            member.setCreatedAt(LocalDateTime.now());
            em.persist(member); //영속상태
        }

        em.flush(); //insert 쿼리 실행 , DB영구반영
        em.clear(); //영속 상태 엔티티 모두 비우기
    }

    @Test
    void test1(){
        Member member = em.find(Member.class, 1L);
        System.out.println(member);

        Member member2 = em.find(Member.class, 1L);
        System.out.println(member2);

        System.out.println(member == member2);
        System.out.println("member : " + System.identityHashCode(member));
        System.out.println("member : " + System.identityHashCode(member2));

        member.setUserName("(수정)사용자1");
        //em.flush(); //UPDATE 쿼리 수행
        //값 변경, 삭제 상태 변경 후 해당 데이터를 조회 -> 암묵적으로 flush();
        Member member3 = em.find(Member.class, 1L);
        System.out.println(member3);
    }
}

참고)

값 변경, 삭제 상태 변경 후 해당 데이터를 조회 👉 암묵적으로 flush();

6. 영속성 컨텍스트

7. 엔티티의 생명주기

  • 1차 캐시
  • 동일성 보장
  • 영속성 컨텍스트 쓰기 지연 SQL 저장소
  • 트랜잭션을 지원하는 쓰기 지연

JPQL(Java Persistence Query Language)

모든 DB플랫폼에 호환
조회 결과가 영속 상태(변화감지)

8. 설정하기

DDL_AUTO
none : 아무런 변경 X
create : 애플리케이션 시작시에 기존 테이블 DROP, 새로 생성
create-drop : 애플리케이션 시작시에 기존 테이블 DROP, 새로 생성, 종료시에도 DROP
update : 기존 테이블 DROP X, 변경 사항만 반영(제거 X)
validate : 기존 테이블 DROP X, 변경 사항 체크(변경 사항이 있으면 예외 발생)

  • 개발시 : create, update
  • 배포 서버 : none, validate

application.yml

server:
  port: 3000

spring:
  #데이터베이스 설정
  datasource:
    driver-class-name: oracle.jdbc.driver.OracleDriver
    url: jdbc:oracle:thin:@localhost:1521:XE
    username: ${db.username}
    password: ${db.password}

  # JPA 설정
  # JPA 설정
  jpa:
    properties:
      hibernate:
        show_sql: true #실행하는 SQL을 콘솔에 출력
        format_sql: true #실행되는 SQL의 들여쓰기 및 줄 개행
        use_sql_comments: true
    hibernate:
      ddlAuto: create #테이블 자동생성

  #로거설정
logging:
  level:
    org:
      hibernate:
        type: trace

테스트, 연습 데이터베이스는 h2를 사용하기 때문에 프로필을 따로 설정.

application-test.yml

server:
  port: 3000

spring:
  #데이터베이스 설정
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:test
    username: sa
    password:

  # JPA 설정
  jpa:
    properties:
      hibernate:
        show_sql: true #실행하는 SQL을 콘솔에 출력
        format_sql: true #실행되는 SQL의 들여쓰기 및 줄 개행
        use_sql_comments: true
    hibernate:
      ddlAuto: create #테이블 자동생성

  #로거설정
  logging:
    level:
      org:
        hibernate:
          type: trace
profile
안녕하세요!

0개의 댓글