๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
BackEnd๐ŸŒฑ/Spring

default method๋กœ JpaRepository ์ข€ ๋” ์šฐ์•„ํ•˜๊ฒŒ ์จ๋ณด๊ธฐ

by ์•ˆ์ฃผํ˜• 2023. 11. 16.

๊ฐœ์š”

Spring Data JPA์—์„œ JpaRepository ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ Java 8์—์„œ ๋„์ž…๋œ default method๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์ข€ ๋” ๊น”๋”ํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Optional ์ œ๊ฑฐํ•˜๊ธฐ

Spring Data JPA์˜ findByXX ๋ฉ”์„œ๋“œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ Optional์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ด๋กœ ์ธํ•ด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—์„œ Optional ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์ถ”๊ฐ€์ ์ธ ์ž‘์—…์ด ํ•„์š”ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ์ด๋Ÿด ๋•Œ default ๋ฉ”์„œ๋“œ๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์ด ๋ฌธ์ œ๋ฅผ ์šฐ์•„ํ•˜๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

public interface UserRepository extends JpaRepository<User, Long> {
    // Default ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ findById์˜ Optional์„ ๋‚ด๋ถ€์ ์œผ๋กœ ์ฒ˜๋ฆฌ
    default User findUserById(Long id) {
        return findById(id).orElseThrow(() -> new DataNotFoundException("User not found with id: " + id));
    }
}

 

๋ฉ”์„œ๋“œ๋ช… ๊ฐ„์†Œํ™”ํ•˜๊ธฐ

Spring Data JPA๋ฅผ ์‚ฌ์šฉํ•˜๋‹ค ๋ณด๋ฉด ๋ณต์žกํ•œ ์ฟผ๋ฆฌ ๋•Œ๋ฌธ์— ๋ฉ”์„œ๋“œ๋ช…์ด ๊ธธ์–ด์ ธ ๊ฐ€๋…์„ฑ์„ ํ•ด์น˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ์ด๋Ÿด ๋•Œ๋„ default ๋ฉ”์„œ๋“œ๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๊ธด ๋ฉ”์„œ๋“œ๋ช…์„ ๊ฐ„๊ฒฐํ•˜๊ณ  ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

public interface ProductRepository extends JpaRepository<Product, Long> {
    // ๊ธฐ์กด์˜ ๊ธด ์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œ
    List<Product> findAllByCategoryAndPriceGreaterThanEqualAndPriceLessThanEqualOrderByPriceAsc(String category, BigDecimal minPrice, BigDecimal maxPrice);

    // Default ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ„๊ฒฐํ•œ ๋ฉ”์†Œ๋“œ๋ช… ์ œ๊ณต
    default List<Product> findProductsByCategoryAndPriceRange(String category, BigDecimal minPrice, BigDecimal maxPrice) {
        return findAllByCategoryAndPriceGreaterThanEqualAndPriceLessThanEqualOrderByPriceAsc(category, minPrice, maxPrice);
    }
}

 

๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ํ†ตํ•ฉ

์—ฌ๋Ÿฌ ๊ธฐ๋ณธ ์ œ๊ณต ๋ฉ”์„œ๋“œ๋ฅผ ํ•˜๋‚˜์˜ ๊ณ ์ฐจ ์ž‘์—…์œผ๋กœ ๊ฒฐํ•ฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ๋‹ค๋งŒ Spring Data JPA์˜ Repository๋Š” Data Access Layer์˜ ์ผ๋ถ€๋กœ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€์˜ ์ƒํ˜ธ์ž‘์šฉ๋งŒ์„ ๋‹ด๋‹นํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ถ€๋ถ„์€ ์„œ๋น„์Šค ๋ ˆ์ด์–ด์—์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ด๋‹ค.

public interface UserRepository extends JpaRepository<User, Long> {
    
    // ์‚ฌ์šฉ์ž ID๋กœ ์‚ฌ์šฉ์ž๋ฅผ ์ฐพ๊ณ , ์กด์žฌํ•  ๊ฒฝ์šฐ ์—ฐ๋ฝ์ฒ˜ ์ •๋ณด๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋ฉ”์†Œ๋“œ
    default void updateUserContact(Long userId, String newContact) {
        findById(userId).ifPresent(user -> {
            user.setContact(newContact);
            save(user);
        });
    }
}

 

์ฃผ์˜ํ•ด์•ผ ํ•  ์ 

์ฝ”ํ‹€๋ฆฐ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์กฐ๊ธˆ ๋‹ฌ๋ผ์ง„๋‹ค. ์ฝ”ํ‹€๋ฆฐ์—์„œ๋Š” ์ž๋ฐ”์˜ default method๋ฅผ ์ง์ ‘ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋‹ค์‹œ ๋งํ•ด ์ฝ”ํ‹€๋ฆฐ์˜ ์ธํ„ฐํŽ˜์ด์Šค์—์„œ๋Š” ๊ธฐ๋ณธ ๊ตฌํ˜„์„ ๋ฉ”์„œ๋“œ์— ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ด๋Š” ์ž๋ฐ”์˜ default method์™€ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

  • ์ž๋ฐ”์˜ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์ธํ„ฐํŽ˜์ด์Šค์— ์„ ์–ธ๋œ default method๋ฅผ 'interface' ํด๋ž˜์Šค ํŒŒ์ผ์— ์ง์ ‘ ํฌํ•จ์‹œํ‚ค๋ฉฐ, ์ด ๋ฉ”์„œ๋“œ๋“ค์€ ์ผ๋ฐ˜ ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ์ฒ˜๋Ÿผ 'invokespecial' ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ˜ธ์ถœ๋œ๋‹ค.
  • ์ฝ”ํ‹€๋ฆฐ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ๊ฐ ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•ด ์Šคํƒœํ‹ฑ ๋ฉ”์„œ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ด๋“ค์„ 'DefaultImpls'๋ผ๋Š” ๋‚ด๋ถ€ ํด๋ž˜์Šค์— ํฌํ•จ์‹œํ‚จ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ํด๋ž˜์Šค์—์„œ๋Š” ์ด๋Ÿฌํ•œ ์Šคํƒœํ‹ฑ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ default method์˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•œ๋‹ค.

์‹ค์ œ๋กœ ์ฝ”ํ‹€๋ฆฐ ํ™˜๊ฒฝ์—์„œ JpaRepository๋ฅผ ์ƒ์†ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค์— ๋ฉ”์„œ๋“œ ๊ตฌํ˜„๋ถ€๋ฅผ ํฌํ•จํ•˜๋ฉด, ์ปดํŒŒ์ผ ๊ณผ์ •์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

No property betweenOsVer found for type ${EntityName}

์ด๋Š” Spring Data JPA๊ฐ€ "์ฟผ๋ฆฌ ๋ฉ”์„œ๋“œ" ๊ธฐ๋Šฅ์„ ํ†ตํ•ด JpaRepository๋ฅผ ์ƒ์†ํ•œ ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜๋ ค๋ฉด ๋ฉ”์„œ๋“œ ์ด๋ฆ„์ด find…By, read…By, count…By ๋“ฑ ์‚ฌ์ „์— ์ •์˜๋œ ๋„ค์ด๋ฐ ๊ทœ์น™์„ ๋”ฐ๋ผ์•ผ ํ•˜๋Š”๋ฐ, ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์ฟผ๋ฆฌ๋ฅผ ์ •์˜ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๊ณ ๋ คํ•ด default method๋Š” "์ฟผ๋ฆฌ ๋ฉ”์„œ๋“œ" ๋Œ€์ƒ์—์„œ ์ œ์™ธ๋˜์–ด ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์ฝ”ํ‹€๋ฆฐ์€ default method๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋“  ๋ฉ”์„œ๋“œ์— "์ฟผ๋ฆฌ ๋ฉ”์„œ๋“œ"๊ฐ€ ์ ์šฉ๋˜๋ฉฐ, ๋„ค์ด๋ฐ ๊ทœ์น™์„ ๋”ฐ๋ฅด์ง€ ์•Š๋Š” ๋ฉ”์„œ๋“œ๋Š” ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

๊ฒฐ๊ตญ, ์ฝ”ํ‹€๋ฆฐ์—์„œ JpaRepository๋ฅผ ์ƒ์†ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค์— ๋ฉ”์„œ๋“œ ๊ตฌํ˜„๋ถ€๋ฅผ ํฌํ•จํ•˜๋ ค๋ฉด, ์ž๋ฐ”์˜ default method์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๋ง์ด๋‹ค.

์ฝ”ํ‹€๋ฆฐ์—์„œ JpaRepository dafult method๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์•„๋ž˜์˜ ๊ธ€์„ ์ฐธ๊ณ ํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

๋Œ“๊ธ€