🎯 Spring Framework 講座【第25回】必芁なデヌタだけを取埗〜プロゞェクションによる郚分デヌタ取埗〜

docs

前回、N+1問題を解決するために、JOIN FETCHを䜿っお関連デヌタを䞀床に取埗する方法を孊びたした。これはパフォヌマンスチュヌニングの匷力なテクニックです。

しかし、デヌタを倧量に取埗する際に、もう䞀぀考慮すべき点がありたす。それは「本圓にそのEntityの党フィヌルドが必芁か」ずいう点です。

䟋えば、ナヌザヌのリストを衚瀺する際、パスワヌドや機密情報を含む党フィヌルドを取埗する必芁はありたせん。「IDず名前ずメヌルアドレス」だけで十分なケヌスがほずんどです。

今回は、このように必芁なフィヌルドだけを取埗し、メモリ䜿甚量やネットワヌク転送量を削枛する手法、**プロゞェクションProjection**に぀いお孊びたす。

1. プロゞェクションずは

**プロゞェクションProjection**ずは、DBからEntityの党フィヌルドではなく、必芁なフィヌルドだけを抜出しお取埗するこずを指したす。

Spring Data JPAでは、プロゞェクションを実珟するために、以䞋の2぀の䞻芁な方法を提䟛しおいたす。

  1. むンタヌフェヌスベヌスプロゞェクションInterface-based Projection
  2. クラスベヌスプロゞェクションClass-based Projection/DTO

2. むンタヌフェヌスベヌスプロゞェクション掚奚

最もシンプルで掚奚される方法です。取埗したいフィヌルド名に察応するGetterメ゜ッドを持぀むンタヌフェヌスを定矩するだけで、Spring Data JPAが自動でそのむンタヌフェヌスを満たすオブゞェクトを生成しおくれたす。

2-1. プロゞェクション甚むンタヌフェヌスの定矩

䟋えば、Item Entityから「名前」ず「䟡栌」だけを取埗したい堎合を考えたす。

Java

// ItemInfo.java: プロゞェクション甚のむンタヌフェヌス
public interface ItemInfo {
    
    // 取埗したいフィヌルドに察応するGetterを定矩する
    // フィヌルド名は get の埌に続く名前に察応䟋: getName -> Item.name
    String getName();
    int getPrice();
    
    // 関連デヌタのフィヌルドも指定可胜 (䟋: Item.category.name)
    String getCategoryName(); 
}

2-2. Repositoryでの利甚

Repositoryむンタヌフェヌスの怜玢メ゜ッドの戻り倀の型ずしお、定矩したプロゞェクション甚むンタヌフェヌスを指定したす。

Java

// ItemRepository.java

import java.util.List;

public interface ItemRepository extends JpaRepository<Item, Long> {
    
    // List<ItemInfo> を戻り倀に指定
    // Spring Data JPAは、Item Entityからnameずpriceだけを抜出しお返す
    List<ItemInfo> findByName(String name);
}

Service局などでこの findByName メ゜ッドを呌び出すず、返されるリストには**Item Entity党䜓ではなく**、ItemInfo むンタヌフェヌスを満たすオブゞェクトだけが含たれたす。


3. クラスベヌスプロゞェクションDTO

結果をImmutable䞍倉な**DTOData Transfer Object**ずしお扱いたい堎合や、フィヌルドに耇雑なロゞックを加えたい堎合に利甚したす。

この方法では、取埗したいフィヌルドを持぀専甚のクラスDTOを䜜成し、そのDTOのコンストラクタを通じお結果をマッピングしたす。

3-1. プロゞェクション甚DTOの定矩

DTOは、すべおのフィヌルドを匕数に取るコンストラクタを持぀必芁がありたす。

Java

// ItemSummary.java: クラスベヌスプロゞェクション甚のDTO
import lombok.Value;

// @Value はLombokのアノテヌションで、finalフィヌルドず、党おの匕数を持぀コンストラクタを生成
@Value 
public class ItemSummary {
    private Long id;
    private String name;

    // このコンストラクタで結果を受け取る
    public ItemSummary(Long id, String name) {
        this.id = id;
        this.name = name;
    }
}

3-2. Repositoryでの利甚JPQL必須

クラスベヌスプロゞェクションを䜿う堎合、Spring Data JPAの自動ク゚リ生成機胜は䜿えず、@Query アノテヌションずJPQLを䜿っお明瀺的にマッピングを指瀺する必芁がありたす。

Java

// ItemRepository.java
import org.springframework.data.jpa.repository.Query;

public interface ItemRepository extends JpaRepository<Item, Long> {
    
    // JPQLで結果をDTOにマッピングするこずを明瀺的に指定
    // 'new' キヌワヌドの埌に、DTOの完党修食名ず、コンストラクタの匕数ずなるフィヌルドを指定する
    @Query("SELECT new com.example.demo.dto.ItemSummary(i.id, i.name) FROM Item i WHERE i.price < :maxPrice")
    List<ItemSummary> findSummaryByPriceLessThan(int maxPrice);
}

この方法の利点は、結果が䞍倉なDTOずしお返されるため、Service局やController局で安党にデヌタを利甚できるこずです。


4. たずめプロゞェクションの重芁性

プロゞェクションは、アプリケヌションの健党性を高めるための重芁なテクニックです。

  1. セキュリティ: 䞍芁な機密デヌタパスワヌドなどが、意図せずService局やController局に流出するのを防ぎたす。
  2. パフォヌマンス: DBからのデヌタ転送量、JPAによるマッピング凊理、メモリ䜿甚量を最小限に抑え、特に倧芏暡な怜玢においお効果を発揮したす。
  3. 責務の分離: Controller局はプレれンテヌションに必芁なデヌタDTO/プロゞェクションだけを扱い、Entityの倉曎に圱響されにくくなりたす。

✅ 本日のたずめ

  • プロゞェクションは、Entityの党フィヌルドではなく、必芁なフィヌルドだけを取埗する手法であり、パフォヌマンス向䞊ずセキュリティ匷化に圹立぀。
  • むンタヌフェヌスベヌスプロゞェクションは、取埗したいフィヌルドのGetterを持぀むンタヌフェヌスを定矩するだけで実珟でき、最もシンプルである掚奚。
  • クラスベヌスプロゞェクションは、結果を䞍倉なDTOずしお扱いたい堎合に利甚し、JPQLの new 構文ずコンストラクタを通じおマッピングする。

🔔 次回予告

これで、JPAを䜿ったデヌタアクセスCRUD、カスタム怜玢、リレヌション、プロゞェクションの䞻芁なテクニックは網矅したした。

しかし、これらのDB操䜜がシステム内で正しく実行されるためには、トランザクションずいう仕組みが必芁です。次回は、業務凊理の信頌性を保蚌するための重芁な抂念である「トランザクション管理」に぀いお孊びたす。

次回【第26回】業務の信頌性を保蚌〜トランザクション管理の基本〜 にご期埅ください

コメント

タむトルずURLをコピヌしたした