Chapter1-3. JPA 소개, 영속성 관리

김신영·2022년 11월 11일
0

JPA

목록 보기
1/14
post-thumbnail
post-custom-banner

JDBC

JdbcUserRepository.java

  • DataSource

  • Connection

  • Statement

  • PreparedStatement

  • ResultSet

  • RowMapper

  • 모든 쿼리 수행에 대해 템플릿 코드 패턴

  • Jdbc API 예시 코드

    Connection conn = null;
    PreparedStatement pstm = null;
    ResultSet rs = null;
    
    try {
    	// 1. Connection
        conn = dataSource.getConnection();
        conn.setTransactionIsolation(TRANSACTION_SERIALIZABLE);
        conn.setAutoCommit(false);
    
        log.info("{} {}", conn, pstm);
    
    	// 2. Statement
        pstm = conn.prepareStatement("SELECT * FROM SPRING_USER");
    
    	// 3. Execute Statement
        rs = pstm.executeQuery();
    
    	// 4. ResultSet Row Mapping
        while (rs.next()) {
            int userId = rs.getInt(USER_TABLE.getColumn(0));
            String userName = rs.getString(USER_TABLE.getColumn(1));
            User user = new User(userId, userName);
            users.add(user);
        }
    } catch (SQLException e) {
        log.error(e.getMessage());
        throw e;
    } finally {
    	// 5. Close Connection
        closeConnection(conn, pstm, rs);
    }
    
  • Jdbc Connection close 예시 코드

    private void closeConnection(
    Connection conn, PreparedStatement pstm, ResultSet rs) {
    	try {
    		if (rs != null) {
    			rs.close();
    		}
    	} catch (SQLException e) {
    		e.printStackTrace();
    	}
    
    	try {
    		if (pstm != null) {
    			pstm.close();
    		}
    	} catch (SQLException e) {
    		e.printStackTrace();
    	}
    
    	try {
    		if (conn != null) {
    			conn.close();
    		}
    	} catch (SQLException e) {
    		e.printStackTrace();
    	}
    }
    

JdbcTemplate

  • JdbcTemplate 예시 코드
    JdbcTemplateUserRepository.java

  • 오직 쿼리와 쿼리 파라미터만 신경쓰면 된다.

  • ResultSet에 대한 rowMapping도 설정해줘야 한다.

NamedParameterJdbcTemplate

Mybatis

  • xml을 통해서 Row Mapping

객체지향 모델 vs 데이터베이스 모델

  • 객체는 참조를 사용해서 다른 객체와 연관관계를 가지고 참조에 접근해서 연관된 객체를 조회한다.

  • 테이블은 외래 키를 사용해서 다른 테이블과 연관관계를 가지고 조인을 사용해서 연관된 테이블을 조회한다.

  • SQL을 직접 다루면 처음 실행하는 SQL에 따라 객체 그래프를 어디까지 탐색할 수 있는지 정해진다.
    - 이는 굉장히 데이터베이스에 의존적이고, 비지니스 개발에 제약사항이 된다.

https://oopy.lazyrockets.com/api/v2/notion/image?src=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F8f25c399-9902-4219-99e6-6e5845aaab40%2F_2020-06-21__2.16.02.png&blockId=487fb674-63e2-44b2-8716-b20eaff16ec0

JPA

Java Persistence API

Java 진영의 ORM 기술에 대한 API 표준 명세

ORM

Object Relational Mapping

객체와 관계형 데이터베이스를 매핑

// INSERT
entityManager.persist(member);

// SELECT
Member member = entityManager.find(Member.class, 1001L);

// UPDATE
member.setName("guest");

// DELETE
member.remove(member);

https://blog.kakaocdn.net/dn/bx2NGK/btqyHU02hk5/YPQn3ZdeWOwlk2H0K6GD8K/img.png

https://velog.velcdn.com/images%2Fyoho98%2Fpost%2Ffb8f90c7-a234-4502-a275-331582cd4869%2FJPA 동작 - 저장.png

EntityManager

https://oopy.lazyrockets.com/api/v2/notion/image?src=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F0a1978bd-745a-42b6-9c34-41330e3ac06c%2F_2020-07-19__6.12.24.png&blockId=d5be3ce2-cd1a-46e5-8c54-75bec5e65812

  • EntityManager 예시 코드

    import org.hibernate.Transaction;
    
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.EntityTransaction;
    import javax.persistence.Persistence;
    
    public abstract class JpaMainTemplate {
        protected EntityManagerFactory emf;
        protected EntityManager em;
        protected EntityTransaction tx;
    
        public void run() {
            run("test");
        }
    
        public void run(String persistenceUnitName) {
            emf = Persistence.createEntityManagerFactory(persistenceUnitName);
    
            em = emf.createEntityManager();
    
            tx = em.getTransaction();
            tx.begin();
    
            try {
                logic(em);
    
                System.out.println("===== BEFORE COMMIT =====");
                tx.commit();
                System.out.println("===== AFTER COMMIT =====");
    
            } catch (Exception e) {
                System.out.println("===== BEFORE ROLLBACK =====");
                tx.rollback();
                e.printStackTrace();
                System.out.println("===== AFTER ROLLBACK =====");
            } finally {
                em.close();
            }
    
            emf.close();
        }
    
        abstract public void logic(EntityManager em);
    
    }

Persistence Context

Entity를 영구 저장하는 환경

Entity Lifecyle

new/transient (비영속)

  • Persistence Context와 전혀 관계가 없는 상태

manageed (영속)

  • Persistence Context에 저장된 상태

detached (준영속)

  • Persistence Context에 저장되었다가, 현재는 분리된 상태

removed (삭제)

  • Persistence Context에서 삭제 요청된 상태

    https://blog.kakaocdn.net/dn/9TmXh/btq4cf7NDf1/8Ih7QbsUqZtGzK50KYIRTk/img.png

Persistence Context 특징

  • Persitence ContextEntity를 식별자 값(@Id)으로 구분한다.
  • Persistence Context에 저장된 Entity들은 flush시점에 데이터베이스에 저장된다.

Persistence Context 기능

  • 1차 캐시 기능 제공
  • 동일성 보장
  • transactional write-behind (쓰기 지연 기능)
  • dirty checking (변경 감지 기능)
  • lazy loading (지연 로딩)

Flush

  • 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화하는 작업
  • 쓰기 지연 SQL 저장소에 모인 쿼리들을 데이터베이스에 보낸다.

Entity 조회

https://velog.velcdn.com/cloudflare/seungho1216/69f24fb7-a660-4e9d-84bc-35cd5164ae0b/1차캐시2.png

Entity 등록

https://velog.velcdn.com/images%2Fjin0849%2Fpost%2F56747ddc-e6fb-4d3f-827b-0720c40388af%2F3.png

https://velog.velcdn.com/post-images%2Fconatuseus%2Feb6c9c30-d09c-11e9-b0db-1597a34a142f%2Fimage.png

Entity 수정

  • JPA는 기본적으로 엔티티의 모든 필드를 업데이트 한다.
    - 모든 필드를 사용하므로, 데이터베이스에 보내는 데이터 전송량이 증가한다. (단점)
    - 수정 쿼리가 항상 같으므로, 애플리케이션 로딩 시점에 수정 쿼리를 미리 생성해두고 재사용 가능 (장점)

@DynamicUpdate , @DynamicInsert

  • 필드가 많거나 저장되는 내용이 너무 크면, 수정된 필드만 사용해서 동적으로 UPDATE SQL을 생성한다.
  • 컬럼이 대략 30개 이상일 경우, 사용 추천

https://img1.daumcdn.net/thumb/R800x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdG1iTX%2FbtqFa7GzKP5%2FtCELwKVoc1dz9DgjNN58CK%2Fimg.png

Flush

영속성 컨텍스트의 변경 내용을 데이터 베이스에 동기화하는 것

Persistence Contextfmf Flush하는 3가지 방법

  • em.flush()
  • tx.commit()
    - 트랙잭션 커밋 시 플러시가 자동 호출된다.
  • JPQL 쿼리 실행시 플러시가 자동 호출 된다.
    - em.createQuery("${JPQL}").getResultList()
    - JPQL은 SQL로 변환되어 데이터베이스에서 엔티티를 조회하므로, 이전에 변경된 데이터들을 데이터 베이스에 반영해야 한다.

FlushModeType

  • FlushModeType.AUTO
    - 커밋이나 쿼리를 실행할 때, Flush 수행 (기본값)
  • FlushModeType.COMMIT
    - 커밋할 때만 Flush 수행

Entity를 준영속 상태로 전환

  • em.detach(entity)
    - 특정 엔티티만 준영속 상태로 전환
  • em.clear()
    - 영속성 컨텍스트를 초기화
  • em.close()
    - 영속성 컨텍스트를 종료

https://leejaedoo.github.io/assets/img/detach.jpg

준영속 상태 Entity를 merge

![https://velog.velcdn.com/images%2Fwisepine%2Fpost%2Fdee93008-d00b-4f89-9917-caca33b00b09%2Fimage.png%5D(https%3A%2F%2Fimages.velog.io%2Fimages%2Fwisepine%2Fpost%2Fdee93008-d00b-4f89-9917-caca33b00b09%2Fimage.png)

profile
Hello velog!
post-custom-banner

0개의 댓글