JpaRepository에 default method를 사용해보자.

sinryuji·2025년 2월 11일
post-thumbnail

Java 8에 도입된 default method 기능을 이용해서 JpaRepository의 사용성을 업그레이드 해봅시다.

💡 default method란?

원래 인터페이스는 기능에 대한 선언만을 수행하므로 실제 로직을 구현할 수 없습니다. 하지만 Java 8에 새로 생긴 default method 기능을 통해 인터페이스에서도 로직을 구현할 수 있게 되었습니다.

Optional 제거

public interface UserRepository extends JpaRepository<User, Long> {
    default User findUserById(long id) {
        return findById(id).orElseThrow(
                () -> new IllegalArgumentException("User not found")
        );
    }

JpaRepository findBy 함수들은 모두 Optional을 반환합니다. 그래서 공통 에러 처리 같은 경우도 불가피하게 service layer로 올라오는 경우가 많은데 위와 같이 default method를 통해 Optional을 제거하며 동시에 에러 처리도 할 수 있습니다.

메소드명 간소화

public interface ProductRepository extends JpaRepository<Product, Long> {
    List<Product> findAllByUserAndProductFolderList_FolderIdAndMypriceGreaterThanEqualOrderByCreatedAt(User user, Long folderId, int price);

    default List<Product> findAllByUserAndFolderIdAndPrice(User user, Long folderId, int price) {
        return findAllByUserAndProductFolderList_FolderIdAndMypriceGreaterThanEqualOrderByCreatedAt(user, folderId, price);
    }
}

쿼리 메소드를 이용하다보면 위와 같이 메소드명이 답도 없이 길어질 때가 많은데, 그 경우에도 default method를 통해 쿼리 메소드를 wrapping 하여 메소명을 간소화 할 수 있습니다.

비즈니스 로직 처리

public interface ProductRepository extends JpaRepository<Product, Long> {
    default Product findProductById(Long id) {
        return findById(id).orElseThrow(
                () -> new IllegalArgumentException("Not found product")
        );
    }

    default Product findProductsByIdAndIncreasingHit(Long id) {
        Product product = findProductById(id);
        product.setHit(product.getHit() + 1);
        return product;
    }
}

게시판 등을 구현하다보면 조회수를 구현하게 되는데, Entity를 조회해온 후 조회수를 증가시켜야 할 경우도 있고 아닌 경우도 있습니다. 그럴 경우에도 위와 같이 두 개의 default method를 구현해서, 해당 Entity가 없을 경우 에러 처리를 함과 동시에 조회수를 증가하며 가져올 수도 있습니다. 물론 findProductsByIdAndIncreasingHit()를 호출하는 service layer의 함수에는 반드시 @Transactionl을 붙여야 Dirty-checking이 수행 되어 hit가 증가합니다.

profile
응애 개발자입니다.

0개의 댓글