Spring - JPA, 영속성 컨텍스

김상엽·2024년 1월 29일
0

Spring

목록 보기
7/26
post-thumbnail

TIL

ORM

  • ORM(Object-Relational Mapping)은 객체와 DB의 관계를 매핑 해주는 도구이다.

JPA

  • JPA(Java Persistence API)는 자바 ORM 기술에 대한 표준 명세이다.
  • JPA는 애플리케이션과 JDBC 사이에서 동작한다.
  • JPA를 사용하면 DB 연결 과정을 직접 개발하지 않아도 자동으로 처리해준다.
  • 또한 객체를 통해 간접적으로 DB 데이터를 다룰 수 있기 때문에 매우 쉽게 DB 작업을 처리할 수 있다.

트랜잭션

  • DB 데이터들의 무결성과 정합성을 유지하기 위한 하나의 논리적 개념이다.
  • 여러 개의 SQL이 하나의 트랜잭션에 포함될 수 있다.
  • 모든 SQL이 성공적으로 수행이 되면 DB에 영구적으로 변경을 반영하지만 SQL 중 단 하나라도 실패한다면 모든 변경을 되돌린다.
  • JPA에서 이러한 트랜잭션의 개념을 적용하기 위해서는 EntityManager에서 EntityTransaction을 가져와 트랜잭션을 적용할 수 있다.
  • EntityTransaction et = em.getTransaction();
    • EntityTransaction을 가져와 트랜잭션을 관리할 수 있다.
  • et.begin();
    • 트랜잭션을 시작하는 명령어
  • et.commit();
    • 트랜잭션의 작업들을 영구적으로 DB에 반영하는 명령어
  • et.rollback();
    • 오류가 발생했을 때 트랜잭션의 작업을 모두 취소하고, 이전 상태로 되돌리는 명령어

Entity

  • JPA에서 관리되는 클래스 즉, 객체를 의미한다.
  • Entity 클래스는 DB의 테이블과 매핑되어 JPA에 의해 관리된다.

@Entity

  • @Entity : JPA가 관리할 수 있는 Entity 클래스로 지정할 수 있다.
    • @Entity(name = "클래스명") : Entity 클래스 이름을 지정할 수 있다. (default: 클래스명)
    • JPA가 Entity 클래스를 인스턴스화 할 때 기본 생성자를 사용하기 때문에 반드시 현재 Entity 클래스에서 기본 생성자가 생성되고 있는지 확인해야 한다.

@Table

  • @Table : 매핑할 테이블을 지정해준다.
  • @Table(name = "테이블이름") : 매핑할 테이블의 이름을 지정할 수 있다. (default: Entity 명)

@Column

  • @Column(name = "컬럼이름") : 필드와 매핑할 ****테이블의 컬럼을 지정할 수 있다. (default: 객체의 필드명)
  • @Column(nullable = false) : 데이터의 null 값 허용 여부를 지정할 수 있다. (default: true)
  • @Column(unique = true) : 데이터의 중복 값 허용 여부를 지정할 수 있다. (default: false)
  • @Column(length = 500) : 데이터 값(문자)의 길이에 제약조건을 걸 수 있다. (default: 255)

@Id

  • @Id : 테이블의 기본 키를 지정해준다.
    • 이 기본 키는 영속성 컨텍스트에서 Entity를 구분하고 관리할 때 사용되는 식별자 역할을 수행한다.

@GeneratedValue

@GeneratedValue 옵션을 추가하면 기본 키 생성을 DB에 위임할 수 있다.

  • @GeneratedValue(strategy = GenerationType.IDENTITY)
    • auto_increment 조건이 추가된다.
    • 해당 옵션을 추가해주면 개발자가 직접 id 값을 넣어주지 않아도 자동으로 순서에 맞게 기본 키가 추가된다.

영속성 컨텍스트

  • Entity 객체를 효율적으로 쉽게 관리하기 위해 만들어진 공간이다.
  • 직접 SQL을 작성하지 않아도 JPA를 사용하여 DB에 데이터를 저장하거나 조회할 수 있으며 수정, 삭제 또한 가능하다.

EntityManager

  • 영속성 컨텍스트에 접근하여 Entity 객체들을 조작하기 위해서는 EntityManager가 필요하다.
  • EntityManager를 사용해서 Entity를 저장하고 조회하고 수정하고 삭제할 수 있다.
  • EntityManager는 EntityManagerFactory를 통해 생성하여 사용할 수 있다.

EntityManagerFactory

  • EntityManagerFactory는 일반적으로 DB 하나에 하나만 생성되어 애플리케이션이 동작하는 동안 사용된다.
  • EntityManagerFactory를 만들기 위해서는 DB에 대한 정보를 전달해야한다.
    • 정보를 전달하기 위해서는 /resources/META-INF/ 위치에 persistence.xml 파일을 만들어 정보를 넣어두면 된다.

1차 캐시

  • 영속성 컨텍스트는 내부적으로 캐시 저장소를 가지고 있다.
  • 캐시 저장소는 Map 자료구조 형태로 되어있다.
    - key에는 @Id로 매핑한 기본 키 즉, 식별자 값을 저장한다.
    - value에는 해당 Entity 클래스의 객체를 저장한다.
  • 영속성 컨텍스트는 캐시 저장소 Key에 저장한 식별자값을 사용하여 Entity 객체를 구분하고 관리한다.

쓰기 지연 저장소(ActionQueue)


JPA는 쓰기 지연 저장소를 만들어 SQL을 모아두고 있다가 트랜잭션 commit 후 한번에 DB에 반영한다.

  • flush() : 영속성 컨텍스트의 변경 내용들을 DB에 반영하는 역할을 수행한다.

변경 감지(Dirty Checking)

  • JPA는 영속성 컨텍스트에 Entity를 저장할 때 최초 상태(LoadedState)를 저장한다.
    • 트랜잭션이 commit되고 em.flush(); 가 호출되면 Entity의 현재 상태와 저장한 최초 상태를 비교한다.
    • 변경 내용이 있다면 Update SQL을 생성하여 쓰기 지연 저장소에 저장하고 모든 쓰기지연 저장소의 SQL을 DB에 요청한다.
    • 마지막으로 DB의 트랜잭션이 commit 되면서 반영된다.

Entity의 상태

  • 비영속(Transient) : 영속성 컨텍스트에 저장되지 않아 JPA의 관리를 받지 않는 상태
    • new 연산자를 통해 인스턴스화 된 Entity 객체
  • 영속(Managed) : 영속성 컨텍스트에 저장하여 관리되고 있는 상태
    • persist(entity) : 비영속 Entity를 EntityManager를 통해 영속성 컨텍스트에 저장
  • 준영속(Detached) : 영속성 컨텍스트에 저장되어 관리되다가 분리된 상태
    • detach(entity) : 특정 Entity만 준영속 상태로 전환한다.
    • clear() : 영속성 컨텍스트를 완전히 초기화한다.
    • close() : 영속성 컨텍스트를 종료합니다.
    • merge(entity) : 전달받은 Entity를 사용하여 새로운 영속 상태의 Entity를 반환
  • 삭제(Removed)
    • remove(entity) : 삭제하기 위해 조회해온 영속 상태의 Entity를 파라미터로 전달받아 삭제 상태로 전환한다.

Spring Data JPA

  • JPA를 쉽게 사용할 수 있게 만들어놓은 하나의 모듈
    • JPA를 추상화시킨 Repository 인터페이스를 제공한다.
  • Repository 인터페이스Hibernate와 같은 JPA구현체를 사용해서 ****구현한 클래스를 통해 사용된다.
  • @PersistenceConext 애너테이션을 사용하면 자동으로 생성된 EntityManager를 주입받아 사용할 수 있다.
  • @Transactional 애너테이션을 클래스나 메서드에 추가하면 쉽게 트랜잭션 개념을 적용할 수 있다.
    • @Transactional(propagation)에서 트랜잭션 전파 옵션을 지정할 수 있다.

SimpleJpaRepository

  • Spring Data JPA에서는 JpaRepository 인터페이스를 구현하는 클래스를 자동으로 생성해준다.
    • Spring 서버가 뜰 때 JpaRepository 인터페이스를 상속받은 인터페이스가 자동으로 스캔이 되면,
    • 해당 인터페이스의 정보를 토대로 자동으로 SimpleJpaRepository 클래스를 생성해 주고, 이 클래스를 Spring ‘Bean’으로 등록한다.
  • 따라서 인터페이스의 구현 클래스를 직접 작성하지 않아도 JpaRepository 인터페이스를 통해 JPA의 기능을 사용할 수 있다.

JPA Auditing

  • @MappedSuperclass
    • JPA Entity 클래스들이 해당 추상 클래스를 상속할 경우 createdAt, modifiedAt 처럼 추상 클래스에 선언한 멤버변수를 컬럼으로 인식할 수 있다.
  • @EntityListeners(AuditingEntityListener.class)
    • 해당 클래스에 Auditing 기능을 포함시켜 준다.
  • @CreatedDate
    • Entity 객체가 생성되어 저장될 때 시간이 자동으로 저장된다.
    • 최초 생성 시간이 저장되고 그 이후에는 수정되면 안되기 때문에 updatable = false 옵션을 추가한다.
  • @LastModifiedDate
    • 조회한 Entity 객체의 값을 변경할 때 변경된 시간이 자동으로 저장된다.
    • 처음 생성 시간이 저장된 이후 변경이 일어날 때마다 해당 변경시간으로 업데이트된다.
  • @Temporal
    • 날짜 타입(java.util.Date, java.util.Calendar)을 매핑할 때 사용한다.
    • DB에는 Date(날짜), Time(시간), Timestamp(날짜와 시간)라는 세 가지 타입이 별도로 존재한다.
      • DATE : ex) 2023-01-01
      • TIME : ex) 20:21:14
      • TIMESTAMP : ex) 2023-01-01 20:22:38.771000

Query Methods

Spring Data JPA에서는 메서드 이름으로 SQL을 생성할 수 있는 Query Methods 기능을 제공한다. Query Methods 는 메서드의 파라미터를 통해 SQL에 필요한 값을 동적으로 받아 처리할 수 있다.
예시) findAllByUsernameOrderByModifiedAtDesc(String username)

  • 테이블에서 수정 시간을 기준으로 username의 데이터를 내림차순으로 가져오는 SQL을 실행하는 메서드

오늘의 회고

지금까지는 TIL의 분량을 어느정도 조절하려고 강의의 진도를 조절하였다.
그런데 생각해보니 TIL의 분량때문에 하루의 공부량이 제한된다는 느낌을 받았다.
그래서 이제부터는 분량걱정없이 강의를 빠르게 듣는쪽으로 하려고한다.
이번주내로 숙련주차를 완강하고 개인과제를 진행하려고 한다.

profile
개발하는 기록자

0개의 댓글