[Spring Data JPA] 확장 기능
사용자 정의 Repository
- 스프링 데이터 JPA Repository는 인터페이스만 정의하고, 구현체는 스프링이 자동 생성
- 스프링 데이터 JPA가 제공하는 인터페이스를 직접 구현하면 구현해야 하는 기능이 너무 많음
- 다양한 이유로 인터페이스의 메서드를 직접 구현하고 싶다면..
- JPA 직접 사용(
EntityManager
) - 스프링 JDBC Template 사용
- MyBatis 사용
- 데이터베이스 커넥션 직접 사용
- Querydsl 사용
- JPA 직접 사용(
구현
사용자 정의 인터페이스
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();
사용자 정의 구현 클래스
- 규칙 : Repository 인터페이스 이름 +
Impl
- 스프링 데이터 JPA가 인식해서 스프링 빈으로 등록
[참고]
실무에서는 주로 QueryDSL이나 SpringJdbcTemplate을 함께 사용할 때 사용자 정의 Repository 기능 자주 사용
[참고]
항상 사용자 정의 Repository가 필요한 것은 아니고, 그냥 임의의 Repository를 만들어도 된다.
예를들어 MemberQueryRepository를 인터페이스가 아닌 클래스로 만들고 스프링 빈으로 등록해서 그냥 직접 사용해도 된다. 이 경우에는 스프링 데이터 JPA와는 아무런 관계 없이 별도로 동작한다.
사용자 정의 Repository(최신)
스프링 데이터 2.x부터는 사용자 정의 구현 클래스에 Repository 인터페이스 이름 + Impl
을 적용하는 대신에 사용자 정의 인터페이스 명 + Impl
방식도 지원한다.
예를 들어 위 예제의 MemberRepositoryImpl
대신에 MemberRepositoryCustomImpl
같이 구현해도 된다.
최신 사용자 정의 인터페이스 구현 예제
@RequiredArgsConstructor
public class MemberRepositoryCustomImpl implements MemberRepositoryCustom {
private final EntityManager em;
@Override
public List<Member> findMemberCustom() {
return em.createQuery("select m from Member m")
.getResultList();
}
}
기존 방식보다 이 방식이 사용자 정의 인터페이스 이름과 구현 클래스 이름이 비슷하므로 더 직관적이다. 추가로 여러 인터페이스를 분리해서 구현하는 것도 가능하기 때문에 새롭게 변경된 이 방식을 사용하는 것을 더 권장한다.
Auditing
- 엔티티를 생성, 변경할 때 변경한 사람과 시간을 추적하고 싶다면..
- 등록일
- 수정일
- 등록자
- 수정자
순수 JPA
등록일과 수정일 적용
@MappedSuperclass
@Getter
public class JpaBaseEntity {
@Column(updatable = false)
private LocalDateTime createDate;
private LocalDateTime updateDate;
@PrePersist
public void prePersist() {
LocalDateTime now = LocalDateTime.now();
createDate = now;
updateDate = now;
}
@PreUpdate
public void preUpdate() {
updateDate = LocalDateTime.now();
}
}
public class Member extends JpaBaseEntity {}
확인 코드
@Test
void JpaBaseEntity() throws InterruptedException {
// given
Member member = new Member("member1");
memberRepository.save(member); // @PrePersist
Thread.sleep(100);
member.setUsername("member2");
em.flush(); // @preUpdate
em.clear();
// when
Member findMember = memberRepository.findById(member.getId()).get();
// then
System.out.println("findMember.createdDate = " + findMember.getCreatedDate());
System.out.println("findMember.updatedDate = " + findMember.getUpdatedDate());
}
출력 값
findMember.createDate = 2022-06-25T17:07:06.533483
findMember.updateDate = 2022-06-25T17:07:06.634725
JPA 주요 이벤트 어노테이션
- @PrePersist, @PostPersist
- @PreUpdate, @PostUpdate
스프링 데이터 JPA
설정
@EnableJpaAuditing
-> 스프링 부트 설정 클래스에 적용해야함
@EntityListeners(AuditingEntityListener.class)
-> 엔티티에 적용
사용 어노테이션
@CreatedDate
@LastModifiedDate
@CreatedBy
@LastModifiedBy
스프링 데이터 Auditing 적용
등록일, 수정일, 등록자, 수정자
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
@Getter
public class BaseEntity {
@CreatedDate
@Column(updatable = false)
private LocalDateTime createDate;
@LastModifiedDate
private LocalDateTime lastModifiedDate;
@CreatedBy
@Column(updatable = false)
private String createBy;
@LastModifiedBy
private String lastModifiedBy;
}
등록자, 수정자를 처리해주는 AuditorAware
스프링 빈 등록
DataJpaApplication.java
@Bean
public AuditorAware<String> auditorProvider() {
return () -> Optional.of(UUID.randomUUID().toString());
}
실무에서는 세션 정보나, 스프링 시큐리티 로그인 정보에서 ID를 받음
[참고]
실무에서 대부분의 엔티티는 등록시간, 수정시간이 필요하지만, 등록자, 수정자는 없을 수도 있다. 그래서 다음과 같이 Base 타입을 분리하고, 원하는 타입을 선택해서 상속한다.
public class BaseTimeEntity {
@CreateDate
@Column(updatable = false)
private LocalDateTime createdDate;
@LastModifiedDate
private LocalDateTime lastModifiedDate;
}
---
public class BaseEntity extends BaseTimeEntity {
@CreatedBy
@Column(updatable = false)
private String createdBy;
@LastModifiedBy
private String lastModifiedBy;
}
<출처 : 인프런 - 실전! 스프링 데이터 JPA(김영한)>
댓글남기기