[Spring] 23. 06.02 Spring Data Jpa 복습 사용자 정의 리포지토리 구현

hyewon jeong·2023년 6월 2일
0

TIL

목록 보기
130/138

1. 사용자 정의 리포지토리 구현

  • 스프링 데이터 JPA 리포지토리는 인터페이스만 정의하고 구현체는 스프링이 자동 생성
  • 스프링 데이터 JPA가 제공하는 인터페이스를 직접 구현하면 구현해야 하는 기능이 너무 많음
    다양한 이유로 인터페이스의 메서드를 직접 구현하고 싶다면?
    JPA 직접 사용( EntityManager )
    스프링 JDBC Template 사용
    MyBatis 사용
    데이터베이스 커넥션 직접 사용 등등...
    Querydsl 사용

사용자 정의 인터페이스


  public interface MemberRepositoryCustom {
      List<Member> findMemberCustom();
}

사용자 정의 인터페이스 구현 클래스

  @RequiredArgsConstructor
  public class MemberRepositoryImpl implements MemberRepositoryCustom {
      private final EntityManager em;
      @Override
      public List<Member> findMemberCustom() {
          return em.createQuery("select m from Member m")
                  .getResultList();
} }

사용자 정의 인터페이스 상속

  public interface MemberRepository
           extends JpaRepository<Member, Long>, MemberRepositoryCustom {
}

사용자 정의 메서드 호출 코드

  List<Member> result = memberRepository.findMemberCustom();

1-1. 사용자 정의 구현 클래스

규칙:

1-1-1. 리포지토리 인터페이스 이름 + Impl

(현재 사용자정의 리포지토리 인터페이스 명 + Impl 도 가능하다. 이 방법이
더 직관적이다. 추가로 여러 인터페이스를 분리해서 구현하는 것도 가능하기 때문에 새롭게 변경된 이 방식을 사용하는 것을 더 권장한다.)

1-1-2. 스프링 데이터 JPA가 인식해서 스프링 빈으로 등록

참고: 실무에서는 주로 QueryDSL이나 SpringJdbcTemplate을 함께 사용할 때 사용자 정의 리포지토리 기능 자주 사용

참고: 항상 사용자 정의 리포지토리가 필요한 것은 아니다. 그냥 임의의 리포지토리를 만들어도 된다. 예를들어 MemberQueryRepository를 인터페이스가 아닌 클래스로 만들고 스프링 빈으로 등록해서 그냥 직접 사용해도 된다. 물론 이 경우 스프링 데이터 JPA와는 아무런 관계 없이 별도로 동작한다.

2. Auditing

엔티티를 생성, 변경할 때 변경한 사람과 시간을 추적하고 싶으면?

  • 등록일
  • 수정일
  • 작성자
  • 수정자

2-1. 순수 jpa 를 통한 Auditing

JpaBaseEntity.class

@MappedSuperclass // 속성(데이터)만을 상속 받아 쓸 수 있도록 함 
@Getter
public class JpaBaseEntity {

  @Column(updatable = false)
  LocalDateTime createdDate;
  LocalDateTime lastModifiedDate;

  @PrePersist
  public void PrePersist(){ //영속성컨텍스트 일어나기 전에 시행
    LocalDateTime now = LocalDateTime.now();
    createdDate = now;
    lastModifiedDate = now;
  }

 @PreUpdate
  public void PreUpdate(){ // 업데이트 일어나기 전에 실행
    lastModifiedDate = LocalDateTime.now();
 }

}

Member.class

public class Member extends JpaBaseEntity {

2-2 스프링 데이터 jpa 를 통한 Auditing

설정

@EnableJpaAuditing 스프링 부트 설정 클래스에 적용해야함

@EntityListeners(AuditingEntityListener.class)

엔티티에 적용

사용 어노테이션

@CreatedDate
@LastModifiedDate
@CreatedBy
@LastModifiedBy

⚡️ 실무에서 대부분의 엔티티는 등록시간, 수정시간이 필요하지만, 등록자, 수정자는 없을 수도 있다.
그래서 다음과 같이 Base 타입을 분리하고, 원하는 타입을 선택해서 상속한다.

  • 해결 법 : 시간관련 데이터 클래스와 작성자 데이터 클래스를 분리하여 만든 후 상속관계로 사용하면 좋다.

BaseTimeEntity.class (등록시간, 수정시간)

@MappedSuperclass
@Getter
@EntityListeners(AuditingEntityListener.class) // 이벤트 리스너 추가
public class BaseTimeEntity {

  @CreatedDate
  @Column(updatable = false)
  LocalDateTime createdTime;

  @LastModifiedDate
  LocalDateTime LastModifiedTime;

}

등록자, 수정자를 처리해주는 AuditorAware 스프링 빈 등록

    @Bean
    public AuditorAware<String> auditorProvider() {
        return () -> Optional.of(UUID.randomUUID().toString());
    }

실무에서는 세션 정보나, 스프링 시큐리티 로그인 정보에서 ID를 받음

BaseEntity.class

@MappedSuperclass
@Getter
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity extends BaseTimeEntity{
  // 작성자와 수정자를 추적하고 싶다면 Application에 코드추가 필요함
  @CreatedBy
  @Column(updatable = false)
  String createBy;

  @LastModifiedBy
  String LastModifiedBy;

}

참고: 저장시점에 등록일, 등록자는 물론이고, 수정일, 수정자도 같은 데이터가 저장된다. 데이터가 중복 저장되는 것 같지만, 이렇게 해두면 변경 컬럼만 확인해도 마지막에 업데이트한 유저를 확인 할 수 있으므로 유지보수 관점에서 편리하다. 이렇게 하지 않으면 변경 컬럼이 null 일때 등록 컬럼을 또 찾아야 한다.

참고로 저장시점에 저장데이터만 입력하고 싶으면 @EnableJpaAuditing(modifyOnCreate = false) 옵션을 사용하면 된다.

전체 적용

@EntityListeners(AuditingEntityListener.class) 를 생략하고 스프링 데이터 JPA 가 제공하는 이벤트를 엔티티 전체에 적용하려면 orm.xml에 다음과 같이 등록하면 된다.

  META-INF/orm.xml
    <?xml version=1.0” encoding="UTF-8?>
    <entity-mappings xmlns=“http://xmlns.jcp.org/xml/ns/persistence/orm”
                     xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
                     xsi:schemaLocation=“http://xmlns.jcp.org/xml/ns/persistence/
    orm http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd”
                     version=2.2">
        <persistence-unit-metadata>
            <persistence-unit-defaults>
                <entity-listeners>
                    <entity-listener
    class="org.springframework.data.jpa.domain.support.AuditingEntityListener/>
                </entity-listeners>
            </persistence-unit-defaults>
        </persistence-unit-metadata>
    </entity-mappings>

참고
김영한 spring data Jpa 강의 자료

profile
개발자꿈나무

0개의 댓글