[JPA]エージェント(Proxy)


JPAでオブジェクトを問い合わせる方法は2つあります.
(どちらの方法もEntityManagerで定義されている方法です.)

1. em.find()


データベースから実際のエンティティ・オブジェクトを問い合わせる

2. em.getReference()


クエリーデータベース・クエリーを遅らせるダミー・エンティティ(エージェント)オブジェクト
ここで、getReference()メソッドは、プロキシオブジェクトを問い合わせるためのメソッドであり、プロキシの事前定義は、JPAでのみ使用される限定概念ではなくプロキシである.この記事では、JPAで使用されているエージェントについて重点的に紹介します.
エージェントの特徴は次のとおりです.
-実際のクラスを継承して作成されます.
-実際のレベルと同じ外観です.
-実際のオブジェクトとエージェントオブジェクトを区別せずに使用できます.
-プロキシオブジェクトは、実際のオブジェクトの参照(ターゲット)を保持します.
-プロキシオブジェクトによってメソッドが呼び出されると、プロキシオブジェクトは実際のオブジェクトのメソッドを呼び出します.

以上のプロパティでは、プロキシオブジェクトが実際のオブジェクトの参照を保持するプロパティについてさらに説明します.
targetはgetReference()を使用してプロキシオブジェクトをインポートするときから初期化されますか?
正解じゃない最初のエージェントオブジェクトのtargetには空の値がありますが、そのオブジェクトに必要な値を取得すると初期化されます.
🎈サンプルコード
Member member = new Member();
member.setUsername("member1");
em.persist(member);

em.flush();
em.clear();


Member findMember = em.getReference(Member.class, member.getId());

// getClass() 메소드의 결과를 출력해보자
System.out.println("findMember.getClass() = " + findMember.getClass());

// 어느 시점에 초기화가 될까? 예측해보자
System.out.println("findMember.getUsername() = " + findMember.getUsername());
🎉結果
findMember.getClass() = class jpabook.jpashop.domain.Member$HibernateProxy$PIBDFjyQ

Hibernate: 
    select
        member0_.MEMBER_ID as MEMBER_I1_0_0_,
        member0_.TEAM_ID as TEAM_ID3_0_0_,
        member0_.USERNAME as USERNAME2_0_0_,
        team1_.TEAM_ID as TEAM_ID1_1_1_,
        team1_.name as name2_1_1_ 
    from
        Member member0_ 
    left outer join
        Team team1_ 
            on member0_.TEAM_ID=team1_.TEAM_ID 
    where
        member0_.MEMBER_ID=?
        
findMember.getUsername() = member1
前述したように、getClass()メソッドを出力した結果、出力されるのは純粋なメンバークラスではなく、Member$HibernateProxy$PIBFjyQというエージェントクラスであることがわかります.
(この出力の前にクエリクエリが失われていないことに注意してください.)
重要なのは、プロキシオブジェクトのターゲットがnullのままであることです.
次の行を見てみましょう.getUsername()メソッドを呼び出しています.(targetがnullの場合、このメソッドはどのように呼び出されますか?)
実際のオブジェクトを要求するデータです.その前にJPAはProxyオブジェクトを待つことができますが、これ以上はできません.当たり前の結果だろう.今は実際のデータが必要だから!そこでこのときselect文を実際に実行しgetUsername()の結果member 1を出力する.

これに関連して、エージェントの追加の特徴は次のとおりです.
-プロキシオブジェクトを最初に使用したときにのみ初期化
-エージェントオブジェクトを初期化すると、エージェントオブジェクトは実際のエンティティにはなりません.初期化後、エージェントオブジェクトから実際のエンティティにアクセスできます.
-プロキシオブジェクトは元のエンティティを継承するので、タイプをチェックするときに特に注意してください(==比較に失敗し、instance ofを使用します).
-永続性コンテキストで見つかったエンティティが既に存在する場合、em.getReference()を呼び出しても実際のエンティティが返されます.
-エージェントが半永久的な状態にある場合、永続性コンテキストでヘルプが得られず、エージェントを初期化すると問題が発生します.
上記の特徴は、実際のサンプルコードに従って一つ一つ検証することをお勧めします.
最初に**エージェント**について言及したのは、JPAの概念だけではありません.複数のプログラミング言語やフレームワークで使用される設計モデルと見なすことができ、プログラミングテクニックと見なすこともできる.では
JPAでプロキシモードを使用する理由何のために使われているのでしょうか.
JPAでは、エンティティの問合せ時に即座にロードおよび遅延ロードをロードするという重要な概念があります.各概念を理解することはJPAを用いる重要な部分であり,JPAは内部でエージェントを利用してこの重要な概念を実現した.そこで,この点を正しく理解するために,まずエージェントを事前作業により理解した.次の記事では、エージェントの概念に基づいて、即時ロードと遅延ロードを理解します.