[JPA]管理とエージェントの関連付け


第8章

  • エージェントとインスタントロード、遅延ロード
    オブジェクトは、オブジェクトシェイプを使用して関連するオブジェクトを参照します.ただし、オブジェクトはデータベースに格納されているため、関連オブジェクトを思う存分閲覧することは難しい.JPAインプリメンテーションはエージェント技術を用いてこの問題を解決する.
  • 8.1エージェント(Proxy)

  • 遅延ロード機能を使用するには、프록시 객체
  • JPA規格明細は、遅延ロードの実現方法をJPA実装体に委任している.したがって,これから現れるコンテンツは仮想現エンティティに関するコンテンツである.ネットワークには,エージェントを用いて遅延ロードを用いる方法とバイトコードを用いる方法がある.

    8.1.1エージェントインフラストラクチャ

    // Persistence Context 에 Entity가 없으면 데이터베이스를 조회
    // 엔티티를 사용하지 않아도 데이터베이스를 조회함
    Member member = em.find(Member.class, "member1");
    
    // 엔티티를 직접 사용하는 시점까지 데이터베이스 조회를 미룸
    Member member = em.getReference(Member.class, "member2");

    プロキシオブジェクトのフィーチャー

  • エージェントの初回使用時한 번만 초기화
  • 2,3回も無駄.
  • エージェントオブジェクトを初期化すると、エージェントオブジェクトを介して実際のエンティティにアクセスできます.
  • 프록시가 엔티티로 바뀌는 것이 아니다!!
  • 内部target値で埋めます.
  • (==比較不可・instance of使用-類型比較)
  • オリジナルエンティティを継承する対象、タイプチェック主義
  • 永続性コンテキストに検索するエンティティが既に存在する場合は、em.getReference()エージェントではなく実際のエンティティを呼び出します.
  • 반대로,初期프록시로 조회em.find()とクエリを行うと、エンティティオブジェクトではなくエージェントオブジェクトが返されます!
  • JPA Hibernateはいつも満足しているのでa == :a!
  • 初期化に必要영속성 컨텍스트の助け.
  • プロキシ初期化


    エージェントの初期化は영속성 컨텍스트で行われる.
    実際に使用すると、プロキシオブジェクトの初期化と呼ばれるデータベースをクエリーして実際のエンティティオブジェクトを作成します.
    //Meber Proxy를 반환한다.
    Member member = em.getReference(Member.class, "id1");
    member.getName();
  • 準永久状態初期化操作中にエラー!!
  • Member member = em.getReference...
    
    transaction.commit();
    em.close(); // 영속성 컨텍스트 종료
    
    member.getName();
    
    //결과 
    org.hibernate.LazyInitializationException 예외 발생 !

    プロキシ初期化の検証

  • エージェントインスタンスを初期化するかどうか
  • PersistenceUnitUtil.isLoaded(Object.entity)
  • エージェントクラス検証方法
  • entity.getClass().getName()出力!
  • [...javasist.orHibernateProxy]両方
  • エージェント強制初期化
  • org.hibernate.Hibernate.initialize(entry);
  • 参照!:JPA표준은 강제 초기화가 없음、強制コール:member.getName()
  • エージェントと識別子

    Team team = em.getReference(Team.class, "team1"); // 식별자 보관
    team.getId(); // 초기화되지 않음
  • エージェントオブジェクトに識別子(id)があるため、クエリIdはエージェントを初期化しない.( @Access(AccessType.PROPERTY )
  • @Access(AccessType.FIELD)がgetId()に設定されていてもidのみがクエリされるのか、他のフィールドを利用してプロキシオブジェクトが初期化されるのか分からない.
  • 関連関係を設定するときは識別子値のみを使用するため、プロキシを使用することでデータベースへのアクセス数を減らすことができます.
  • boolean isLoad = PersistenceUnitUtil.isLoaded(entity);
    // 프록시 인스턴스 초기화 여부 확인
  • 8.2即時ロードと遅延ロード


    即時ロード(緊急)

    @Entity
    public class Member {
    
    	@ManyToOne(fetch = FetchType.EAGER)
        @JoinColumn(name= "TEAM_ID")
        private Team team;
        
        // ...
    }
    Member member = em.find(Member.class,"member1");
    Team team = member.getTeam();
    
    // SQL
    SELECT *
    FROM
    	MEMBER M LEFT OUTER JOIN TEAM T
        ON M.TEAM_ID=T.TEAM_ID
    WHERE
    	M.MEMBER_ID = 'member1';
  • 照会でLEFT OUTER JOINが使用されていることがわかります.なぜLEFTOUTER JOINを使ったのでしょうか?まず、チームの会員がいなかったら?社内サインであれば、チームのない会員は照会すらしていません.JPAはこのような状況を考慮して外部結合を使用している.
  • NULL制約とJPA結合ポリシー
    外部結合に比べて、内部結合はパフォーマンスの最適化に役立ちます.内部結合を使用するために、外部キーにNOT NULL制約を設定すると、値が保証されます.
    @JoinColumn(name="TEAM_ID", nullable=false)
    明示されているように、内部結合が使用されます.
    または
    @ManyToOne(fetch = FetchType.EAGER, optional = false )
    @JoinColum(name ="TEAM_ID")
    private Team team;
    
    </br>
    
    ### 지연 로딩(lazy)
    ``` java
    Member member = em.find(Member.class,"member1");
    Team team = member.getTeam();	// 프록시 객체
    team.getName(); // 팀 객체 실제 사용
  • 集合—@ManyToOne、@OneToOne:即時ロード
  • OneToMany,@ManyToMany:遅延ロード-外部結合を無条件に使用!
  • コレクションのFetchTypeEAGER使用時の注意事項
    1.コレクションの即時ロードでは、常に外部結合が使用されます.
    2.コレクションをすぐにロードすることは推奨されません.

    ≪即時ロード|Immediate Load|emdw≫:≪遅延ロードのクリア|Clear Deferred Load|emdw≫

  • 遅延ロード(lazy):エージェントによって関連付けられたエンティティを問合せます.実際にエージェントを購入する場合は、初期化しながらデータベースをクエリーします.
  • 即時ローディング(Eager):直ちに関連するエンティティを問い合わせる.HibernateはできるだけSQLを使用してクエリーを結合します.
  • 8.4永続的移行:CASCADE


    あるエンティティを永続状態にしたい場合は、関連するエンティティも一緒に永続状態にしたい場合は、영속성 전이기능を使用します.JPAはCASCADEオプションで、永続的な変換を提供します.簡単に言えば、永続性遷移を使用する場合、親エンティティをアセンブリする際に、サブエンティティを一緒に格納することもできる.
  • CascadeType.PERSIST
  • @Entity
    public class Parent {
    	@OneToMany( mappedBy = "parent", cascade = CascadeType.PERSIST )
        private List<Child> children = Lists.newArrayList();
    }
    
    private static void save(EntityManager em) {
    
    	Parent parent = new Parent();
        child1.setParent(parent);
        child2.setParent(parent);
        parent.getChildren().addAll(child1,child2);
        
        em.persist(parent);
    }
  • CascadeType.REMOVE
  • Parent findParent = em.find(Parent.class, 1L);
    em.remove(findParent);
  • REMOVEオプションは、外来キーの制約条件を考慮して、子供を先に削除し、親を削除する.
  • 選択肢がない場合は削除부모 Entity外来鍵制限条件により発生외래키 무결성 예외
  • 参考までにCascadeTypePERSIST、REMOVEは、em.persist()、em.remove()を実行してもすぐに移行は発生せず、リフレッシュを呼び出すと移行が発生します.

    8.5孤立オブジェクト


    JPAは、親エンティティに関連付けられていない子エンティティを自動的に削除する機能を提供し、孤児オブジェクトの削除(ORPHAN)と呼ばれています.
    
    //엔티티 
    @OneToMany(mappedBy = "parent", orphanRemoval = true)
    private List<Child> children = new ArrayList<>();
    
    // 코드
    Parent paren = em.find(Parent.class, parentId);
    parent.getChildren().remove(removeObject);
  • 親エンティティの集合から子エンティティの参照を削除すると、自動的に子エンティティが削除されます.
  • 8.6永久転移+孤児対象、ライフサイクル


    CascadeType.All+孤児Removal=trueを併用すると?
  • 親エンティティで子どものライフサイクルを管理できます.
  • 子供を産みたい저장親に登録するだけ.(CASCADE)
  •     Parent parent = em.find(Parent.class, parentId);
        parent.addChild(child1);
  • 子供を삭제親から外しておけばいい.(OrphanRemoval)
  •     Parent parent = em.find(Parent.class, parentId);
        parent.getChildren.remove(removeObject);