beadss / jpa-study

jpa슽터디입니다
1 stars 2 forks source link

JPA 1장 - 3장 요약정리 #2

Open remagine opened 5 years ago

remagine commented 5 years ago

1장 핵심요약

JPA의 필요성

관계형 DB 그리고 객체간 패러다임 불일치

물리적 저장공간에 데이터를 저장하는 관계형 DB의 패러다임

추상화된 객체를 메모리에 구현하는 객체지향언어

관계는 관계형 DB에서는 FK로 객체지향에서는 상속, 다형성, 추상화, 캡슐화로 이뤄진다.

각 패러다임간의 불일치를 프로그래머가 해결해야 하고 비용이 많이 소모된다.

이러한 비용을 JPA가 중간자로 자동화해서 해결하고 있다.

마이바티스 VS JPA

불일치 해결을 위해서는

  1. 쿼리 XML 관리(MAPPER) - INTERFACE
  2. 쿼리문 작성 - XML
  3. PARAM VO, RESULT VO 정의 - CLASS

자바 객체와 DB 테이블간의 맵핑이 필요하고, 마이바티스를 사용하여 관리되고 있다.

JPA는 CLASS와 ANNOTATION으로 제어하며 위 3가지 모두를 JPA를 통해 주입된다.

JPA는 하나의 프레임워크라고 볼 수 있다.

정확히 말하자면 ORM 표준 프레임워크이다.

JPA의 장점

JPA의 단점

2장 JPA 시작

  1. 어노테이션을 활용한클래스 - 테이블 맵핑

@Entity - 클래스 -테이블 간 맵핑을 jpa에 알려준다

@Table - DB의 어떤 테이블인지 명시한다. 생략하면 클래스 명이 테이블명

@Id - 테이블의 pk를 의미

@Column - 필드 - 컬럼간 맵핑 명시, 없으면 필드명 = 컬럼명

  1. persistence.xml

어노테이션을 통한 설정

`package com.sempio.en.config;

import javax.sql.DataSource;

import org.apache.commons.lang3.StringUtils; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.core.task.TaskExecutor; import org.springframework.orm.hibernate5.HibernateTransactionManager; import org.springframework.orm.hibernate5.LocalSessionFactoryBuilder; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.zaxxer.hikari.HikariDataSource;

@Configuration @EnableTransactionManagement public class PersistenceConfig { @Autowired private Environment env;

@Bean
public DataSource dataSource() {
    HikariDataSource ds = new HikariDataSource();
    ds.setDataSourceClassName("org.postgresql.ds.PGSimpleDataSource");

    if (StringUtils.isNotEmpty(env.getProperty("database.server-name"))) {
        ds.addDataSourceProperty("serverName", env.getProperty("database.server-name"));
    }
    ds.addDataSourceProperty("databaseName", env.getProperty("database.database-name"));
    ds.addDataSourceProperty("user", env.getProperty("database.user"));
    if (StringUtils.isNotEmpty(env.getProperty("database.password"))) {
        ds.addDataSourceProperty("password", env.getProperty("database.password"));
    }
    return ds;
}

@Bean
public SessionFactory sessionFactory() {
    LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(dataSource());
    builder.scanPackages("com.sempio.en.entity");
    builder.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQL9Dialect");

    if (env.acceptsProfiles("dev")) {
        builder.setProperty("hibernate.show_sql", "true");
        builder.setProperty("hibernate.format_sql", "true");
    }

    return builder.buildSessionFactory();
}

@Bean
public TaskExecutor taskExecutor() {
    return new SimpleAsyncTaskExecutor();
}

@Bean
public TaskScheduler taskScheduler() {
    return new ThreadPoolTaskScheduler();
}

@Bean
public PlatformTransactionManager transactionManager() {
    return new HibernateTransactionManager(sessionFactory());
}

} `

xml과 동일한 수준의 설정이지만 config 에서 어노테이션으로 관리 위에서는 Hibernate의 Sessin Factory를 사용했다.

  1. 엔티티 매니저 설정

persistence.xml or persistenceConfig.java를 통해 Persistence(생명주기가??) 가 EntityManagerFactory

혹은 SessionFactory를 생성한다

각 Transaction마다 EntityManager가 생성되고, 관리된다

JPQL - SQL을 자바스럽게 표현한 언어라고 생각하면 좋다

  1. 영속성 관리

3.1 요약정리

엔티티 매니저 팩토리 - 생성비용이 큼. 쓰레드 세이프.

엔티티 매니저 - 생성비용 작음. 쓰레드 논세이프.

persistence 설정을 통해 DB와 통신할 자원을 준비하고, 관리하는 것은 ORM 프레임워크

엔티티 매니저의 생명주기는 엔티티 매니저 팩토리

트랜잭션을 관리는 엔티티 매니저

트랜잭션의 시작에서 connection 을 pool에서 획득, 트랜잭션 종료와 함께 반환

3.2 영속성 컨텍스트

사실 객체를 메모리에 영구저장할 수 있다면? 객체지향적 DB가 가능할 것이다.

하지만 실제 데이터들은 메모리에 모두 올릴 수 없다. 너무나 방대하고 메모리는 한정적이며 성능도 저하될 것이다

그러기에 사용할 데이터들만 메모리에 저장하여, 객체처럼 쓰는것

jpa > 자바 영속성 api > 엔티티를 영구저장하는 환경인 것

이 환경이 바로 jpa 영속성 컨텍스트이다.(싱글턴인듯하다)

3.3 엔티티 생명주기

비영속 영속 준영속 삭제

비영속 - db에서 데이터를 불러온적이 없는 상태, 즉 db와 객체간 관계가 맺어진 적이 없다. jpa 영속성 컨텍스트에 생성된 적이 없다

영속 - 영속성 컨텍스트에 저장된 상태. jpa 영속성 컨텍스트는 db에서 데이터를 호출해서 자바 객체와 관계 맺어질 때 생성되고 저장된다. 즉 영속의 근원은 db이고, 영속의 호출은 어플리케이션이다

준영속 - 영속성 컨텍스트에 저장되었다가 분리된 상태. db에서 최초로 데이터가 호출되어 jpa 컨텍스트에 저장되었지만, 강제적으로 이 관계가 분리된 상태. 관계를 다시맺는 영속상태가 되기 위해선, 객체와 db의 데이터의 비교가 필요하고, 일치시키는 작업이 필요하다. 이것이 merge 이며, insert 일수도 update일수도 있다.

삭제 - 삭제된 상태. 정확히 말하면, 데이터를 삭제하고 객체를 삭제한다. 데이터가 먼저 삭제된다.

3.4

영속성 컨텍스트의 특징

pk, id가 반드시 존재한다. - pk가 없는 테이블의 경우??? (hibernate에선 허용하지 않았던 것으로 기억)

Flush -flush > COMMIT 순차적으로 이뤄짐

영속성 컨텍스트의 장점

1차캐쉬 - 변경감지를 위한 기초 동일성보장 - 자바 영속성 api의 기본 전략 트랜잭션을 지원하는 쓰기지연 - connection 자원 효율 증가 변경감지 - 동일성보장과 동일 지연로딩 - 역시 효율증가

1차캐쉬

영속성 컨텍스트 내부의 캐쉬로 1차캐쉬로 불림. 영속 상태의 엔티티는 모두 여기에 저장

영속성 컨텍스트 내부 MAP > 키 : @ID , 값 : 엔티티 인스턴스

JPA는 1차캐쉬 탐색 > 없으면 > DB 탐색 순으로 처리한다.

1차캐쉬 = DB 인스턴스가 동일해야 한다는 가정이 필요하다

(개발자가 DB를 어플리케이션이 아닌 직접 수정하면??)

동일성 보장

동일성 - 실제 인스턴스가 같다. 참조가 같다 동등성 - 인스턴스는 다를 수 있고, 값은 동일하다.

JPA는 @ID별로 인스턴스가 관리되므로, 동일한 @ID로 호출된 객체는 동일성을 가진다.

엔티티 등록 - 쓰기지연

트랜잭션 별로 쿼리는 DB로 FLUSH 된다. 쿼리는 쓰기지연 SQL 저장소에 모여있다가 트랜잭션이 끝나는 시점에

FLUSH 되어 DB로 보내지고, DB는 해당쿼리를 COMMIT한다.

동일성 보장 - 변경감지

변경감지는 사실 동일성 보장을 위한 것으로, 영속상태의 객체에 변경이 일어나면

변경된 엔티티와 엔티티 스냅샷을 비교

변경된 엔티티 기준으로 수정 SQL 생성 > 쓰기 지연 SQL 저장소 저장

트랜잭션이 완료되면, FLUSH를 통해 SQL 전송

DB COMMIT

플러쉬

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

  1. 강제호출

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

  3. JPQL 쿼리 실행시 플러시 자동호출 - JPQL은 영속상태에 있는 객체로 작성된다. 객체가 영속상태가 되기 위해서는 DB에 MERGE되는 것이 먼저이며, MERGE는 FLUSH로 마무리 된다.

준영속

영속상태 객체들을 JPA 컨텍스트에서 삭제하는 것으로

변경감지, 동일성 보장되지 않는 상태로 변경하는 것

detach() - 특정 엔티티를 준영속으로 변경

clear() - 모든 엔티티를 준영속으로 변경

close() - 영속성 컨텍스트 종료, 모든 엔티티 준영속 변경

MERGE

준영속 객체를 영속으로 변경하는 것으로

준영속 객체를 기준으로 DB와 데이터 동기화가 우선적으로 실행(FLUSH-COMMIT)

이후 영속상태가 된다.

MERGE는 비영속 객체도 영속객체로 만들 때 사용된다.