사용자 정의 인터페이스
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();
규칙:
(현재 사용자정의 리포지토리 인터페이스 명 + Impl 도 가능하다. 이 방법이
더 직관적이다. 추가로 여러 인터페이스를 분리해서 구현하는 것도 가능하기 때문에 새롭게 변경된 이 방식을 사용하는 것을 더 권장한다.)
참고: 실무에서는 주로 QueryDSL이나 SpringJdbcTemplate을 함께 사용할 때 사용자 정의 리포지토리 기능 자주 사용
참고: 항상 사용자 정의 리포지토리가 필요한 것은 아니다. 그냥 임의의 리포지토리를 만들어도 된다. 예를들어 MemberQueryRepository를 인터페이스가 아닌 클래스로 만들고 스프링 빈으로 등록해서 그냥 직접 사용해도 된다. 물론 이 경우 스프링 데이터 JPA와는 아무런 관계 없이 별도로 동작한다.
엔티티를 생성, 변경할 때 변경한 사람과 시간을 추적하고 싶으면?
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 {
@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 강의 자료