엔티티 매니저와 영속성 컨텍스트

Yennie·2024년 4월 4일

JPA

목록 보기
3/19

엔티티 매니저

엔티저를 관리해 데이터베이스와 애플리케이션 사이에서 객체를 생성, 수성, 삭제하는 역할을 하며 이런 엔티티 매니저를 만드는 곳이 엔티티 매니저 팩토리이다. 스프링 부트에서는 엔티티 매니저마다 팩토리를 각각 만드는 것이 아니라, 앤티티 매니저를 하나만 생성해서 관리한다. @PersistenceContext 와 @Autowired 애너테이션을 이용해서 사용한다.

앤티티 매니저는 기본적으로 빈을 하나만 생성해서 공유하므로 동시성 문제가 발생할 수 있다. 그래서 실제 엔티티 매니저가 연결하는 프록시 (가짜) 엔티티 매니저를 사용한다. 필요할 때 데이터베이스 트랜잭션과 관련된 실제 엔티티 매니저를 호출한다.

영속성 컨텍스트 (PersistenceContext)

엔티티 매니저는 엔티티를 영속성 컨텍스트에 저장한다는 특징이 있다.
영속성 컨텍스트 JPA의 중요한 특징 중 하나로, 엔티티를 관리하는 가상의 공간이다.
기존에는 데이터 조작을 통해 쿼리를 직접 작성해야 했지만, 스프링 부트에서는 이런 쿼리를 자바코드로 작성하고 JPA가 알아서 쿼리로 변경해주는 것이 매우 편리하다.

1) 1차 캐시
영속성 컨텍스트는 1차 캐시를 가지고 있으며, 이때 캐시의 키는 엔티티의 @Id 애너테이션이 달린 기본키 역할을 하는 식별자이자 값은 엔티티이다. 엔티티를 조회하면 1차 캐시에서 데이터를 조회하고 값이 있으면 반환한다. 값이 없으면 ㄷ이터베이스에서 조회하기 때문에 캐시가 있다면 빠르게 조회가 가능하다.

2) 쓰기 지연
트랜잭션을 커밋하기 전까지 데이터베이스에 실제로 질의문을 보내지 않고 쿼리를 모았다가 트랜잭션을 커밋하면 모았던 뭐리를 한번에 실행하는 것을 의미한다.

3) 변경 감지
트랜젝션을 커밋하면 1차 캐시에 저장되어 있는 엔티티의 값과 현재 엔티티의 값을 비교해서 변경된 값이 있다면 변경 사항을 감지해 변경된 값을 데이터베이스에 자동으로 반영한다. 적당한 묶음으로 쿼리를 요청하여 시스템의 부담을 줄인다.

4) 지연 로딩
쿼리로 요청한 데이터를 어플리케이션에 바로 로딩하는 것이 아니라 필요할 때 쿼리를 날려 조회하는 것을 의미한다.

✅ 데이터 베이스의 접근을 최소화하여 성능을 높일 수 있다는 장점이 있음

엔티티 상태

4가지의 상태

@Autowired
EntityManager em;

1) transit 비영속 상태: 단순히 entity 객체를 생성한 상태

Member member = new Member(1L, “홍길동“)

2) managed 관리 상태

em.persist(member);

3) detached 분리 상태: 더 이상 엔터티를 영속성 컨텍스트에서 관리하고 싶지 않을 때

em.detach(member);

4) removed 삭제 상태: 더이상 객체가 필요없을 때

em.remove(member);

스프링 데이터 JPA

앞에서는 엔티티의 상태를 직접 관리하고 필요한 시점의 커밋 등 개발자가 관리해야할 부분들이 많다. 스프링 데이터는 비즈니스 로직에 더 집중할 수 있게 데이터베이스 사용 기능을 클래스 레벨에서 추상화했다.

스프링 데이터에서 제공하는 인터페이스를 통해 스프링 데이터를 사용할 수 있으며 이 인터페이스에서는 CRUD를 포함한 여러 메서드가 포함되어 있으며, 알아서 쿼리를 만들어준다.

JPA: 스프링 데이터 JPA
몽고디비: 스프링 데이터 몽고디비를 사용

예제코드

@Entity // 엔티티로 지정 만약 name이 이 있다면 그 테이블과 매핑
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED) // 기본 생성자
public class Article {
    @Id // 기본 키 지정
    /* 자동키 생성 방식은 AUTO, IDENTITY, SEQUENCE, TABLE이 있음 
    AUTO (선택한 데이터베이스 방언에 따라 방식을 자동으로 선택_
    IDENTITY (기본키 생성을 데이터 베이스에 위임)
    SEQUENCE (오라클 주로 사용, 데이터베이스 시퀀스를 사용해서 할당)
    TABLE (키 생성 테이블 사용) */
    @GeneratedValue(strategy = GenerationType.IDENTITY)
   
    @Column(name = "id", updatable = false) 
    /* @Column 은 데이터베이스의 칼럼과 필드를 매핑해줌. 
    name: 필드와 매핑할 컬럼 이름, 설정하지 않으면 필드 이름으로 지정
    nullable: null 허용 여부 
    unique: 컬럼의 유니크한 값 여부 디폴트 false
    columnDefinition: 컬럼 정보 설정, default 값을 줄 수 있음
    */
    private Long id;

    // title is not null
    @Column(name = "title", nullable = false)
    private String title;

    @Column(name = "content", nullable = false)
    private String content;

    // 빌더 패턴 방식으로 객체를 생성할 수 있어 편리하다 (롬복)
    @Builder
    public Article(String title, String content) {
        this.title = title;
        this.content = content;
    }
 }

스프링 데이터 JPA에서 사용하는 메서드를 사용한다.

@RequiredArgsConstructor // final이 붙거나 @NotNull이 붙은 필드의 생성자 추가
@Service
public class BlogService {
    private final BlogRepository blogRepository;

    // 블로그 추가하기
    public Article save(AddArticleRequest request) {
        return blogRepository.save(request.toEntity());
    }

}

리포지토리
엔티티에 있는 데이터들을 조회하거나, 저장, 변경, 삭제를 할 때 사용하는 인터페이스로, 스프링 데이터 JPA에서 제공하는 인터페이스인 JpaRepository 클래스를 상속바다 간단하게 구현이 가능하다.

// 엔티티 Article과 엔티티의 PK 타입 Long
public interface BlogRepository extends JpaRepository <Article, Long> {
}
profile
PM | Aspiring SWE | linkedin.com/in/emilyyeeun

0개의 댓글