質問

私はJava Persistence APIとHibernateの初心者です。

違いは何ですか FetchType.LAZYFetchType.EAGER Java Persistence APIで?

役に立ちましたか?

解決

時には2つのエンティティがあり、それらの間に関係があります。たとえば、呼ばれるエンティティがある場合があります University と呼ばれる別のエンティティ Student そして、大学には多くの学生がいるかもしれません:

大学のエンティティには、ID、名前、住所などの基本的なプロパティと、特定の大学の学生のリストを返す学生と呼ばれる収集プロパティがある場合があります。

A university has many students

public class University {
   private String id;
   private String name;
   private String address;
   private List<Student> students;

   // setters and getters
}

これで、データベースから大学をロードすると、JPAはID、名前、およびアドレスフィールドをロードします。ただし、生徒のロード方法については、次の2つのオプションがあります。

  1. 残りのフィールドと一緒にロードするには(つまり、熱心に)、または
  2. あなたが大学に電話するときにそれをオンデマンドでロードする(すなわち怠け者) getStudents() 方法。

大学に多くの学生がいる場合、特に必要でない場合は、すべての学生を一緒にロードすることは効率的ではなく、そのような場合には、実際に必要なときに生徒を積み込んでもらいたいと宣言できます。これは怠zyなロードと呼ばれます。

これが例です students 明示的にマークされています。

@Entity
public class University {

    @Id
    private String id;

    private String name;

    private String address;

    @OneToMany(fetch = FetchType.EAGER)
    private List<Student> students;

    // etc.    
}

そして、これが例です students 怠lazにロードされるように明示的にマークされています:

@Entity
public class University {

    @Id
    private String id;

    private String name;

    private String address;

    @OneToMany(fetch = FetchType.LAZY)
    private List<Student> students;

    // etc.
}

他のヒント

基本的、

LAZY = fetch when needed
EAGER = fetch immediately

EAGER コレクションのロードは、親が獲得した時点で完全にフェッチされることを意味します。だからあなたが持っているなら Course そしてそれは持っています List<Student>, 、すべての生徒が獲得されます データベースから 当時 Course フェッチされています。

LAZY 一方、の内容は List アクセスしようとする場合にのみフェッチされます。たとえば、呼び出すことによって course.getStudents().iterator(). 。のアクセスメソッドを呼び出します List 要素を取得するためにデータベースへの呼び出しを開始します。これは、その周りにプロキシを作成することによって実装されます List (また Set)。したがって、あなたの怠zyなコレクションのために、コンクリートタイプはそうではありません ArrayListHashSet, 、 しかし PersistentSetPersistentList (また PersistentBag)

パフォーマンスとメモリの利用を検討する場合があります。大きな違いの1つは、熱心なフェッチ戦略では、セッションなしでフェッチされたデータオブジェクトを使用できることです。なんで?
セッションが接続されているときに、オブジェクト内の熱心なマークデータを使用すると、すべてのデータが取得されます。ただし、怠zyな読み込み戦略の場合、セッションが切断された場合(後にデータを取得しません(後にデータを取得しません) session.close() 声明)。 Hibernate Proxyによって作成できます。熱心な戦略により、セッションを閉じる後もデータを利用できるようになります。

デフォルトでは、すべてのコレクションとマップオブジェクトについて、フェッチングルールは FetchType.LAZY そして、他のインスタンスについては、それは続きます FetchType.EAGER ポリシー。
簡単に言えば、 @OneToMany@ManyToMany 関係は関連するオブジェクト(コレクションとマップ)を暗黙のうちに取得しませんが、検索操作はフィールドを通じてカスケードされます @OneToOne@ManyToOne ワンズ。

(礼儀:-ObjectDbcom)

私の知る限り、両方のタイプのフェッチはあなたの要件に依存します。

FetchType.LAZY オンデマンドです(つまり、データが必要な場合)。

FetchType.EAGER 即時です(つまり、私たちの要件が来る前に、私たちは不必要に記録を取得しています)

両方 FetchType.LAZYFetchType.EAGER 定義するために使用されます デフォルトのフェッチプラン.

残念ながら、怠zyなフェッチのためのデフォルトのフェッチ計画をオーバーライドすることしかできません。熱心なフェッチングは柔軟性が低く、できます 多くのパフォーマンスの問題につながります.

私のアドバイスは、フェッチはクエリタイムの責任であるため、あなたの協会を熱心にする衝動を抑えることです。したがって、すべてのクエリはを使用する必要があります フェッチ 現在のビジネスケースに必要なもののみを取得するための指令。

から Javadoc:

熱心な戦略は、データを熱心に取得する必要があるという永続プロバイダーのランタイムの要件です。怠zyな戦略は、データが最初にアクセスされたときにゆっくりとフェッチする必要があるという永続プロバイダーのランタイムのヒントです。

たとえば、熱心は怠zyよりも積極的です。怠zyは最初の使用でのみ発生します(プロバイダーがヒントをとる場合)、一方、熱心なもの(5月)が事前に獲得されます。

Lazy Fetch Typeは、明示的にマークしない限り、デフォルトでHibernateによって選択されます Eager フェッチタイプ。より正確で簡潔にするために、違いを以下に記載することができます。

FetchType.LAZY = Getterメソッドを介して呼び出しない限り、これは関係をロードしません。

FetchType.EAGER =これにより、すべての関係がロードされます。

これら2つのフェッチタイプの長所と短所。

Lazy initialization 不必要な計算を回避することにより、パフォーマンスを向上させ、メモリ要件を削減します。

Eager initialization より多くのメモリ消費量を取り、処理速度は遅いです。

そうは言っても、 状況に依存します これらの初期化のいずれかを使用できます。

book.java

        import java.io.Serializable;
        import javax.persistence.Column;
        import javax.persistence.Entity;
        import javax.persistence.GeneratedValue;
        import javax.persistence.GenerationType;
        import javax.persistence.Id;
        import javax.persistence.ManyToOne;
        import javax.persistence.Table;

        @Entity
        @Table(name="Books")
        public class Books implements Serializable{

        private static final long serialVersionUID = 1L;
        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        @Column(name="book_id")
        private int id;
        @Column(name="book_name")
        private String name;

        @Column(name="author_name")
        private String authorName;

        @ManyToOne
        Subject subject;

        public Subject getSubject() {
            return subject;
        }
        public void setSubject(Subject subject) {
            this.subject = subject;
        }

        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getAuthorName() {
            return authorName;
        }
        public void setAuthorName(String authorName) {
            this.authorName = authorName;
        }

        }

subject.java

    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.List;
    import javax.persistence.CascadeType;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.GeneratedValue; 
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.OneToMany;
    import javax.persistence.Table;

    @Entity
    @Table(name="Subject")
    public class Subject implements Serializable{

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="subject_id")
    private int id;
    @Column(name="subject_name")
    private String name;
    /**
    Observe carefully i have mentioned fetchType.EAGER. By default its is fetchType.LAZY for @OneToMany i have mentioned it but not required. Check the Output by changing it to fetchType.EAGER
    */

    @OneToMany(mappedBy="subject",cascade=CascadeType.ALL,fetch=FetchType.LAZY,
orphanRemoval=true)
    List<Books> listBooks=new ArrayList<Books>();

    public List<Books> getListBooks() {
        return listBooks;
    }
    public void setListBooks(List<Books> listBooks) {
        this.listBooks = listBooks;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    }

hibernateutil.java

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {

 private static SessionFactory sessionFactory ;
 static {
    Configuration configuration = new Configuration();
    configuration.addAnnotatedClass (Com.OneToMany.Books.class);
    configuration.addAnnotatedClass (Com.OneToMany.Subject.class);
    configuration.setProperty("connection.driver_class","com.mysql.jdbc.Driver");
    configuration.setProperty("hibernate.connection.url", "jdbc:mysql://localhost:3306/hibernate");                                
    configuration.setProperty("hibernate.connection.username", "root");     
    configuration.setProperty("hibernate.connection.password", "root");
    configuration.setProperty("dialect", "org.hibernate.dialect.MySQLDialect");
    configuration.setProperty("hibernate.hbm2ddl.auto", "update");
    configuration.setProperty("hibernate.show_sql", "true");
    configuration.setProperty(" hibernate.connection.pool_size", "10");
    configuration.setProperty(" hibernate.cache.use_second_level_cache", "true");
    configuration.setProperty(" hibernate.cache.use_query_cache", "true");
    configuration.setProperty(" cache.provider_class", "org.hibernate.cache.EhCacheProvider");
    configuration.setProperty("hibernate.cache.region.factory_class" ,"org.hibernate.cache.ehcache.EhCacheRegionFactory");

   // configuration
    StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
    sessionFactory = configuration.buildSessionFactory(builder.build());
 }
public static SessionFactory getSessionFactory() {
    return sessionFactory;
}
} 

main.java

    import org.hibernate.Session;
    import org.hibernate.SessionFactory;

    public class Main {

    public static void main(String[] args) {
        SessionFactory factory=HibernateUtil.getSessionFactory();
        save(factory);
        retrieve(factory);

    }

     private static void retrieve(SessionFactory factory) {
        Session session=factory.openSession();
        try{
            session.getTransaction().begin();
            Subject subject=(Subject)session.get(Subject.class, 1);
            System.out.println("subject associated collection is loading lazily as @OneToMany is lazy loaded");

            Books books=(Books)session.get(Books.class, 1);
            System.out.println("books associated collection is loading eagerly as by default @ManyToOne is Eagerly loaded");
            /*Books b1=(Books)session.get(Books.class, new Integer(1));

            Subject sub=session.get(Subject.class, 1);
            sub.getListBooks().remove(b1);
            session.save(sub);
            session.getTransaction().commit();*/
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            session.close();
        }

        }

       private static void save(SessionFactory factory){
        Subject subject=new Subject();
        subject.setName("C++");

        Books books=new Books();
        books.setAuthorName("Bala");
        books.setName("C++ Book");
        books.setSubject(subject);

        subject.getListBooks().add(books);
        Session session=factory.openSession();
        try{
        session.beginTransaction();

        session.save(subject);

        session.getTransaction().commit();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            session.close();
        }
    }

    }

main.javaの取得()メソッドを確認してください。主題を得ると、そのコレクション リストブック, 、で注釈が付けられています @OneToMany, 、怠lazにロードされます。しかし、一方で、コレクションの本関連協会 主題, 、で注釈が付けられています @ManyToOne, 、Ealgerly(by [default][1] 為に @ManyToOne, fetchType=EAGER)。 fetchtype.eegerを配置することで動作を変更できます @OneToMany subject.javaまたはfetchtype.lazy on @ManyToOne books.javaで。

public enum fetchType拡張java.lang.enumは、データベースからデータを取得するための戦略を定義します。熱心な戦略は、データを熱心に取得する必要があるという永続プロバイダーのランタイムの要件です。怠zyな戦略は、データが最初にアクセスされたときにゆっくりとフェッチする必要があるという永続プロバイダーのランタイムのヒントです。この実装は、怠zyな戦略ヒントが指定されているデータを熱心に取得することが許可されています。例:@basic(fetch = lazy)保護された文字列getname(){return name; }

ソース

このメモを「Kyung Hwan Min」が上記で言ったことに追加したいと思います。

このシンプルなアーキテクトで春の休憩を使用しているとします。

コントローラー<->サービス<-->リポジトリ

そして、あなたが使用している場合、あなたはいくつかのデータをフロントエンドに返したいです FetchType.LAZY, 、セッションがサービスで閉鎖されているため、コントローラーメソッドにデータを返すと例外が得られます。 JSON Mapper Object データを取得できません。

この問題を解決するための3つの一般的なオプションがあり、設計、パフォーマンス、開発者に依存します。

  1. 最も簡単なのは使用することです FetchType.EAGER, 、そのため、セッションはコントローラー法でまだ生きています。
  2. アンチパターン ソリューション、実行が終了するまでセッションをライブにするために、システム内で大きなパフォーマンスの問題になります。
  3. ベストプラクティスは使用することです FetchType.LAZY からデータを転送するコンバーターメソッドを使用します Entity 別のデータオブジェクトに DTO そして、それをコントローラーに送信するので、セッションが閉じたとしても例外はありません。

@drop-shadow hibernateを使用している場合は、電話することができます Hibernate.initialize() あなたが呼び出すとき getStudents() 方法:

Public class UniversityDaoImpl extends GenericDaoHibernate<University, Integer> implements UniversityDao {
    //...
    @Override
    public University get(final Integer id) {
        Query query = getQuery("from University u where idUniversity=:id").setParameter("id", id).setMaxResults(1).setFetchSize(1);
        University university = (University) query.uniqueResult();
        ***Hibernate.initialize(university.getStudents());***
        return university;
    }
    //...
}

怠zy:それは、子のエンティティを取得する時点で、子どもエンティティを怠lazにフェッチします。子エンティティのプロキシ(cglibまたはその他のユーティリティによって作成された)を取得するだけで、子エンティティの財産にアクセスすると、実際にハイバーネートによってフェッチされます。

熱心:それは親とともに子供のエンティティを取得します。

よりよく理解するためにJBossのドキュメントにアクセスするか、使用できます hibernate.show_sql=true アプリの場合は、Hibernateが発行したクエリを確認してください。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top