Spring data JPA 확장기능

반응형
반응형

Spring data JPA에서는 많은 확장 기능을 제공하고 있다.

사용자 정의 리포지토리 구현 (잡 글)

일반적으로 Spring data JPA에서는  

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

인터페이스를 통해서 JPA를 사용하고 있다.
근데 마이바티스 나 네이티브 쿼리를 사용하는 경우 위 인터페이스는 의미가 없어진다.
왜냐하면, JPA에서 이들을 관리할 수 없기 때문이다. 결국 이들을 사용할때 엔티티와 테이블간의 간극이 발생할 수 있다는 건데
이를 해결하는 방안으로는 강제로 영속성 컨텍스트를 초기화를 시켜줘야 가능하다. 
그러면 위 인터페이스를 이용하면 어떨까?
결론부터 말하면 굉장히 비효율적이다. 아까도 말했듯이 마이바티스나 네이티브 쿼리는 JPA에서 관리를 하지 않고 있다.
따라서 이들을 활용해서 JPA 메소드를 이용해서 만들려고 한다면 이를 상속을 받아 사용해야 된다.

public class NativeRepository implements JpaRepository<Member,Long> {

  @Override
  public List<Member> findAll() {
    return null;
  }

  @Override
  public List<Member> findAll(Sort sort) {
    return null;
  }

  @Override
  public Page<Member> findAll(Pageable pageable) {
    return null;
  }

  @Override
  public List<Member> findAllById(Iterable<Long> longs) {
    return null;
  }

...
}

이들을 새로 정의를 해야 이 메소드를 해당 메소드를 사용할 수 있다.
근데 이들을 사용해야 하는지 의문이 든다.
내가 생각할때는 이들을 JPA와 비슷한 환경에서 이들을 사용하고 싶어서 그런게 아닐까 생각이 든다.
그래서 JPA를 상속을 시키는 방법도 나온거라 추측한다. 그래도 납득이 되지는 않기는 한데
저런거 다 집어치우고 그냥 추가 기능을 추가하기 위해서? 
근데 이거는 아니라고 생각이 드는게 @Query를 사용하면 되는데 굳이 추가 기능으로 이것을 사용하는지 이해가 되지 않는다.
강의는 들은지 시간이 꽤 지나서 까먹었구
내가 생각할때는 환경을 일치하기 위해서 하는 거라 생각이 든다. 왠만하면 환경이 비슷한게 좋지 않을까 생각이 든다.

사용법은 다음과 같다.

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

요렇게 인터페이스를 만들고 이것을 구현하는 클래스만 만들어주면 된다고 한다.

@RequiredArgsConstructor
public class CustomMemberRepositoryImpl implements CustomMemberRepository {

  private final EntityManager em;

  @Override
  public List<Member> findMemberCustom() {
    return em.createQuery("select m from Member m", Member.class).getResultList();
  }
}

지금 같은 경우는 그냥 JPA를 사용할때 저렇게 사용하는 거구
마이바티스같은 경우도 비슷하지 않을까 추측한다. (시간이 없어서 해보지는 못했지만 아무래도 많이 상용할듯)
그리고 저것을 바로 사용하는 것이 아니라 

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

 이렇게만 등록 시켜주면 된다고 한다.

 @Test
  void customTest() {
    System.out.println(memberRepository.findMemberCustom());
  }

근데 이것을 구현하는게 Impl을 무조건 붙여야한다고 하는데 과연 사실일까?
저걸로 테스트한걸로는 정상적으로 쿼리를 출력했다.

public class CustomMemberRepositoryHaHa implements CustomMemberRepository {}

구현체로 이렇게 수정한 결과

java.lang.IllegalStateException: Failed to load ApplicationContext
...

에러가 발생하였디. 이것을 회피하는 방법이 있다고는 하는데 지금은 시간이 없으므로 넘어가자.
결국 정리를 해보자면,
1. 새로운 인터페이스를 만든다.
2. 그것을 구현한 클래스명 + Impl를 붙인다. 새로운 인터페이스를 implements한다.
3. 기존에 만들어있는 JPA인터페이스와 함께 extens 한다.

라고 정리 할 수 있다.

Auditing

이 기능같은 경우는 수정일, 생성일, 수정자, 생성자같은 히스토리성 데이터를 추가할 수 있다.
일단 이 기능같은 경우는 순수 JPA에서는 어떻게 하는지 확인해보자.

@MappedSuperclass
@Getter
public class JpaBaseEntity {

  @Column(updatable = false)
  private LocalDateTime createdDate;
  private LocalDateTime updatedDate;

  @PrePersist
  public void prePersist() {
    LocalDateTime now = LocalDateTime.now();
    createdDate = now;
    updatedDate = now;
  }

  @PreUpdate
  public void preUpdate() {
    updatedDate = LocalDateTime.now();
  }
}

이렇게 작성이 된다고는 하는데 위에서는 생성자와 수정자도 있긴한데 이거 같은경우는 당장은 어려울 것 같다.
할려면 할 수 도 있겠지만, 공부니까 굳이라는 생각이 든다.

특이한건
@MappedSuperclass가 존재하는데 이것의 존재의미는 그냥 상속을 통해 사용한다는 의미다.

이제 이것을 어떻게 Spring data jpa에서는 어떻게 사용할까?

@MappedSuperclass
@Getter
public class JpaBaseEntity {

  @CreatedDate
  @Column(updatable = false)
  private LocalDateTime createdDate;
  @LastModifiedDate
  private LocalDateTime lastModifiedDate;
  @CreatedBy
  @Column(updatable = false)
  private String createdBy;
  @LastModifiedBy
  private String lastModifiedBy;
}

이렇게만 하면 될까? 아쉽지만 아니다.

@EntityListeners(AuditingEntityListener.class)

이걸 추가해줘야 한다.
이 기능은 Auditing이벤트기능을 사용하기 위해서 이것을 사용하는 거라 추측한다.

마지막으로

@EnableJpaAuditing
public class DataJpaApplication {}

이렇게 안하면 동작하지 않는다고 한다.

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

이렇게 해야 수정자와 생성자가 보인다고 한다.
이거는 랜덤UUID이지만 유저ID로 노출하기 위해서는 어떻게 해야 할까 고민된다. 
이것을 글로벌로 지정하는 방법도 있다고 한다.

이 밖에도 Web에 활용되는 것들도 굉장히 많이 제공한다.
예를 들면, JPA로 바로 API로 사용한다던지 
아니면 페이징 기능을 별도로 제공하고 있다. 이 기능들은 재미있지만 이쯤에서 끝내야 할듯 싶다.
컨버터 기능을 웬만해서는 사용을 안하는게 좋다고한다. 페이징은 나중에 시간되면 작성해보자.

반응형

댓글(0)

Designed by JB FACTORY