Spring_JPA

JooH·2024년 2월 26일
0

NHN_BackendAcademy

목록 보기
18/23

Before Starts :
데이터 저장 -> 영속성이라고 함
그와 관련된 프레임 워크 : 영속성 프레임 워크 (DB, File, 외부저장소(Network사용))
R-DB : 관계형 데이터베이스 모델을 자주 사용한다.

1) Spring - data - JPA
2) Spring - Jdbc
3) MyBatis 

등 다양하게 존재한다.

  • 관계형 데이터베이스와 ORM
  • JPA
  • Entity 맵핑

DB 정의

  • 데이터를 효율적으로 관리하기 위한 저장소
  • 특정 조직의 여러 사용자가 데이터를 공유해 사용할 수 있도록 통합 저장된 데이터의 집합
  • 행과 열로 구성된 시트에서 사용자가 정의한 형식으로 데이터를 관리하는 엑셀파일과 유사

관계형 모델

  • 데이터를 테이블(컬럼, 로우)들로 정의
  • 고유키가 각 row를 식별
  • row는 record, tuple로 불림
  • 관계는 서로 다른 테이블 사이의 상호작용에 기반을 두고 형성된 논리적 연결

Column : 데이터의 속성
Row : 컬럼들의 집합
key, primary key, foreign key
Relationship : 테이블 사이의 관계
transaction : data의 일관성을 유지하기 위해 R-DB가 제공하는 기능
SQL : DB를 사용하기 위해 쓰는 query language(DDL, DML, DCL)

H2 Database

  • 자바기반
  • 오픈소스
  • 관계형 데이터베이스

JDBC : R-DB에 저장된 데이터를 접근 및 조작할 수 있게 해주는 자바 API
개발자는 DB종류에 상관 없이 JDBC api만을 이용하면 된다

JDBC 구조

JDBC API

DataSource : Connection 객체를 사용해서 App과 DB 사이의 연결을 해줘, Sequel을 실행할 수 있게 해준다. 하지만 아무나 DB에 접근해서는 안되기 때문에 상세한 정보(host, port, id, pw)를 제공해야 connection을 받아 올 수 있다. Connection Pooling을 일반적으로 제공을 해준다. 따라서 성능에 대한 확장성이 좋다.

  • Statement, PreparedStatement, commit, rollback, close 등 제공
    Statement : 요청이 올 때 마다 parsing을 해줘야함
    PreparedStatement : 미리 parsing된(최초 1번) statement를 가지고 있음

Connection Pool

  • Connection 객체는 생성시 많은 시스템 자원을 요구함
  • 따라서 여러 Connection을 Pool에 모아놓고 관리함
  • 미리 Pool을 생성하고 요청하면 pool에서 connection을 꺼낸 후, close시 pool에 반환

-> 시스템 자원 요구 하는데 필요한 시간을 runtime에 요구하지 않게 됨

Thread-Safe : 멀티쓰레드 환경에서 하나의 공유 자원을 여러 쓰레드가 접근시(running) 문제가 생길 수 있는 상황을 문제가 생기지 않게 처리한것.

즉, Spring MVC Connection pool은 Thread-safe하다. 왜냐? Connection pool의 갯수보다 많은 thread 요청은 wait() 상태로 변해있기 때문이다.

장점 :

  • 데이터베이스에 Connection 을 생성할때 소요되는 시간 및 자원을 줄일 수 있음
  • Connection 수를 제한 할 수 있어 과다한 접속으로 인한 서버 자원 고갈을 예방
    - 적절한 시기에 MySql을 scale-up 하지 않으면 장점이 단점이 될 수 있음
    - 최대 200개만 연결이 가능하다는것은 장점이자 단점
  • 메모리 영역에서 Connection 을 관리하기 때문에 클라이언트가 데이터베이스 작업을 빠르게 진행

구현체 종류

  • Apache Commons DBCP (일반적으로 Legacy System에서 많이 쓰임)
  • Tomcat DBCP (공공 SI, 대기업에서 사용)
  • HikariCP (Spring Boot에서주로 사용)
    *Common, HikariCP를 결국 많이 사용한다

Java에서 data access 기술

  • JDBC api
  • Spring Framework의 JdbcTemplate(JDBC를 한번 감싼 템플릿)
  • MyBatis - SQLmapper framework
  • JPA(ORM)

Spring Framework JdbcTemplate

  • JDBC API 기반
  • JdbcTemplate 을 사용하면 지금까지 Jdbc 를 사용한 코드에서 많은 부분을 Spring Framework 가 대신 처리

DBCP를 사용할 때, 기본 설정(initial size, max total, min total, max Idle)은 통일시키는게 일반적으로 좋다. runtime에 connection의 숫자가 바뀌는것은 좋지 않기 때문

해당 과정으로 잘 연결이 되었는지 확인할 수 있다.

ORM : (Object-Relational Mapping)

  • ORM 프레임워크가 중간에서 객체와 관계형 DB를 Mapping
  • ORM을 이용하면 DBMS 벤더마다 다른 SQL에 대한 종속성(DB마다 제공하는 SQL이 다름)을 줄이고 호환성 향상이 가능

JPA : (Java Persistence API -> Jakarta Persistence API)

구현 : Hibernate, EclipseLink, DataNucleus

  • 사실상 Hibernate가 표준이다(de facto)

JPA를 써야 하는 이유?
SQL 중심적인 개발에서 객체 중심(자바) 으로 개발하기 위해서

  • 패러다임 불일치 해결 : JPA는 객체와 관계형 데이터베이스 사이의 패러다임의 불일치로 인해 발생하는 문제 (상속, 연관관계, 객체 그래프 탐색 등)를 해결

  • 생산성

  • JPA를 쓰면 CRUD를 직접 쓰지 않아도 됨
  • Spring Data JPA를 쓰면 interface선언만으로 쿼리 구현이 가능하기 때문에 CRUD 쿼리 쉽게 대처 가능
  • 유지보수(Maintainence)
  • 컬럼 추가/삭제 시 직접 관련된 CRUD 쿼리를 모두 수저하는 대신 JPA가 관리하는 모델을 수정하면 됨

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

  • 데이터베이스 벤더마다 미묘하게 다른 데이터 타입 / sql은 JPA를 사용하면 손쉽게 해결 가능

Spring Framework와 JPA
Spring Data

  • 다양한 데이터 저장소에 접근을 추상화 하기 위한 Spring 프로젝트
  • JPA, JDBC, Redis, MongoDB, Elasticsearch 등

Spring Data JPA

  • repository 추상화를 통해 interface 선언만으로도 구현 가능
  • 메서드 이름으로 쿼리 생성
  • Web Support (페이징, 정렬, 도메인 클래스 컨버터 기능)

Transaction : 데이터베이스의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위 또는 한꺼번에 모두 수행되어야 할 일련의 연산(query)들을 의미

Transaction 예시) [송금예제] a->b 만원 송금

Transaction 속성) ACID - Atomicity, Consistency, Isolation, Durability

Atomicity : 트랜잭션의 수행결과는 데이터베이스에 전부 반영되거나, 전부 반영되지 않아야 한다
- commit, rollback

Consistency : 트랜잭션 수행 후 데이터 모델의 모든 제약조건을 만족해야 한다
- Data save시 bigint가 저장되어야 하는데, str이 저장되면 안됨
- PK, FK, Unique등...

Isolation : 트랜잭션 수행 시 다른 트랜잭션이 영향을 미치지 않아야 한다
- MultiThread 상황에서 각각의 트랜잭션이 다른 트랜잭션에 영향X
- read uncommited (dirty read)
- read committed
- repeatable read (phantom read)
- serializable

Durability : 트랜잭션의 성공결과는 장애 발생 후에도 변함없이 보관되어야 한다
- 앞서 설명한 영속성) 정상 저장된 데이터는 DBMS가 책임지고 DB에 기록하는 성질

Spring Framework의 트랜잭션 추상화 : PlatformTransactionManager

  • Spring Framework 트랜잭션 추상화의 핵심 interface
public interface PlatformTransactionManager extends TransactionManager {
    TransactionStatus getTransaction(TransactionDefinition definition) /*..*/;
    void commit(TransactionStatus status) throws TransactionException;
    void rollback(TransactionStatus status) throws TransactionException;
}

해당 인터페이스가 있어야 메소드에 @Transactional(AOP)을 달 수 있음

선언적 트랜잭션

@Transactional

*AOP가 정상적으로 동작하기 위해서 어떤 조건 필요?
1) 대상 객체가 Spring Bean(@Service, @Component, @Repository, ...)
- 일반적으로 Service에 usecase를 담기 때문에 주로 Service에 AOP 적용
2) 해당 Method가 Public

*Datasource에 PlatformTransactionManager를 Bean으로 만들고 트랜잭션을 달아줘야함 -> JPAConfig로 변경

JPA를 쓰기 위해....
1) @EnableJpaRepositories(basePackageClasses = RepositoryBase.class) 선언
2) @Configuration 선언
3) LocalContainerEntityManagerFactoryBean 만들기
- LocalContainerEntity 만드는 Bean임
- JPA에서 entity를 관리하고, life cycle 관리 : Entity Manager
- EntityManager에서 지원하는 persist, merge, find, remove 등의 함수 지원
- Entity : Table
4) JPA Vendor 선언 (JpaVendorAdapter)
5) Properties 선언
6) PlatformTransactionManager 선언

EntityManager : 엔터티의 저장, 수정, 삭제, 조회 등 엔터티와 관련된 모든 일을 처리하는 관리자

public interface EntityManager {
    public <T> T find(Class<T> entityClass, Object primaryKey);
    public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties); 
    public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode);
    public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties);

    public void persist(Object entity);
    public <T> T merge(T entity);
    public void remove(Object entity);
    // ...
}

EntityManagerFactory : EntityManager를 생성하는 팩토리

public interface EntityManagerFactory {
  public EntityManager createEntityManager();
  public EntityManager createEntityManager(Map map);
  public EntityManager createEntityManager(SynchronizationType synchronizationType);
  public EntityManager createEntityManager(SynchronizationType synchronizationType, Map map);
  // ...
}

JPA/Hibernate Logging
SQL

  • JPA properties
    - hibernate.show-sql=true : JPA에서 생성해내는 쿼리가 무엇인지 로그로 찍어줌
    - hibernate.format_sql=true : 쿼리가 좀 더 이쁘게 찍힘
  • logback logger
<logger name="org.hibernate.SQL" level="debug" additivity="false">
    <appender-ref ref="console" />
</logger>
  • binding parameters
<logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="trace" additivity="false">
    <appender-ref ref="console" />
</logger>

Entity 맵핑
Entity // Entity Mapping

Entity? JPA를 이용하여 DB Table과 Mapping 할 Class
Entity Mapping? Entity Class에 DB Table과 column, pk, fk 등을 설정하는 것

어노테이션

  • @Entity : JPA가 관리할 객체임을 명시
  • @Table : 맵핑할 DB 테이블 명 지정
  • @Id : 기본 키(PK) 맵핑
  • @Column : 필드와 컬럼 맵핑 (생략 가능)

Entity를 생성시 약속 : NoArgsConstructor, Class 일것(interface, enum 안됨), final을 못씀, @id는 구분자(pk)가 필요함

*final 변수 : 값 변경 불가, final method : 오버라이딩 불가능, final class : 상속 불가능

  • table의 변수이름과 entity의 필드 이름이 같다면 굳이 @Column(name = "")을 달지 않아도 된다

예제)

@Entity
@Table(name = "Members")
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @Column(name = "created_dt")
    private LocalDateTime createdDate;

}

필드와 컬럼 맵핑
@Column

  • 객체 필드를 컬럼에 맵핑 (생략가능)

@Temporal

  • 날짜 타입 맵핑 - Date, Calendar, Time, TimeStamp 등은 @Temporal 붙여줘야함
    하지만 Java8에서 추가된 LocalTime, LocalDate, LocalDateTime은 @Temporal을 붙이지 않아도 된다

*TestCase 작성시 클래스 상단에 @Transactional을 달면 모든 TestCase가 rollback이 된다

기본키 (PK) Mapping 전략

자동생성

  • Table 전략 : 채번 Table을 사용 // DB에 부담을 주게 되어있음.
  • Sequence 전략 : DB Sequence를 사용해 기본키 할당(Oracle)
  • Identity 전략 : 기본키 생성을 DB에 위임(MySql) (AutoIncrement)
  • Auto 전략 : 선택한 DB Dialect에 다라 PK Mapping 전략을 자동으로 선택

직접할당

  • Application에서 직접 PK값을 할당

예제)

public class Item {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "item_id")
    private Long itemId;

    // ...
}
public @interface GeneratedValue {
  GenerationType strategy() default AUTO;
  String generator() default "";

}
public enum GenerationType {
    TABLE, 
    SEQUENCE, 
    IDENTITY, 
    AUTO
}

복합키 (Composite key)

  • @IdClass
    - @IdClass(clazz.Pk.class)
    • @Id를 복합키 컬럼마다 달아줘야 함
    • 추상화한 PK static 클래스를 만들고 PK, Primary, Key등 이름 넣어서 생성하면 된다.
  • @EmbeddedId / @Embeddable
    - 둘중 하나 써서 복합키 구성하면 됨
    - @EmbeddedId달고 실제 class를 가져옴
    • 추상화 클래스에서 @Embeddable을 선언하고 컬럼을 구현해야 한다

IdClass : 직접 Get메소드 가능
EmbeddedId : 조금 추상화된 방식으로 PK가 디자인 된 방식을 사용
두 방식 모두 외부에서 참조할 수 있게 Static으로 구성해야 함 또한 Implements Seralizable 해야함

복합키 클래스 제약조건:

  • PK 제약 조건을 그대로 따름
  • PK 제약 조건
    - The primary key class must be public and must have a public no-arg constructor.
    - The primary key class must be serializable.
    - The primary key class must define equals and hashCode methods.

EntityManager랑 EntityManagerFactory는 1:1 매핑이 되어서 DB를 두개쓰면 Manager도 2개, Factory도 2개다

EntityManagerFactory : EntityManager를 생성하는 팩토리
데이터베이스를 하나만 사용하는 Application은 일반적으로 팩토리를 하나만 쓴다(비용 매우 큼(cpu,memory))
- thread safe

EntityManager : Entity의 저장, 수정, 삭제, 조회 등 Entity와 관련된 모든 일을 처리하는 관리자
- Factory가 생성함 : 생성비용이 낮음
- Thread Safe하지 않다!
- 절대 여러 thread간에 공유하면 안됨
- Transaction의 life-cycle과 정확히 일치함
- 각각의 요청마다 별도의 Manager를 생성해야 함

영속성 컨텍스트(Durability Context) : Entity를 영구저장하는 환경

@PersistenceContext

Entity의 생명주기

비영속, 영속, 준영속, 삭제

비영속(new/transient) : 영속성 컨텍스트와 전혀 관계 없는 상태
- new Foo() << 상태임(persist()) 해야 Manager가 manage 할 수 있게됨

영속(managed) : 영속성 컨텍스트에 저장된 상태
- EntityMageger.persist(new Foo)
- persist, find, merge

준영속(detached) :영속성 컨텍스트에 저장되었다가 분리된 상태
- DB의 상태와 Application의 상태가 다를 때(update ~~ set ~~ 하면 상태가 달라짐)
- detach, clear, close

삭제(removed) : 삭제된 상태
- remove

DB에 데이터 반영 : flush() - transactionManager가 트랜잭션이 끝나면 flush() 해줌

영속성 컨텍스트가 Entity를 관리하면 얻을 수 있는 이점

  • 1차 캐시
  • 동일성 보장
  • 트랜잭션을 지원하는 쓰기 지연
    - delete, update, insert시 flush()가 실행되어야 실제 query로 변환이 됨
    • transaction의 맨 마지막에 실행되므로 쓰기가 지연됨
  • 변경 감지
  • 지연 로딩

0개의 댓글