Разница между FetchType LAZY и EAGER в Java Persistence API?

Я новичок в Java Persistence API и Hibernate.

В чем разница между FetchType.LAZY и FetchType.EAGER в Java Persistence API?

Иногда у вас есть две сущности, и между ними есть отношения. Например, у вас может быть объект под названием «Университет» и другой объект «Студент».

Учреждение университета может иметь некоторые основные свойства, такие как идентификатор, имя, адрес и т. Д., А также свойство, называемое учениками:

 public class University { private String id; private String name; private String address; private List students; // setters and getters } 

Теперь, когда вы загружаете университет из базы данных, JPA загружает для вас свои идентификаторы, имена и адреса. Но у вас есть два варианта для студентов: загрузить его вместе с остальными полями (то есть с нетерпением) или загрузить его по требованию (т.е. лениво), когда вы называете метод getStudents () университета.

Когда в университете много учеников, неэффективно загружать всех своих учеников, когда они не нужны. Поэтому в подобных случаях вы можете заявить, что хотите, чтобы ученики загружались, когда они действительно нужны. Это называется ленивой загрузкой.

В основном,

 LAZY = fetch when needed EAGER = fetch immediately 

EAGER коллекций означает, что они извлекаются полностью в момент, когда их родитель получает. Итак, если у вас есть Course и у него есть List , все ученики будут извлечены из базы данных во время получения Course .

LAZY с другой стороны, означает, что содержимое List выбирается только при попытке получить к ним доступ. Например, вызывая course.getStudents().iterator() . Вызов любого метода доступа в List инициирует вызов базы данных для извлечения элементов. Это реализовано путем создания прокси-сервера вокруг List (или Set ). Таким образом, для ваших ленивых коллекций конкретные типы не являются ArrayList и HashSet , но PersistentSet и PersistentList (или PersistentBag )

Я могу рассмотреть производительность и использование памяти. Одно большое различие заключается в том, что страtagsя EAGER fetch позволяет использовать извлеченный объект данных без сеанса. Зачем?
Все данные извлекаются, когда требуются помеченные данные в объекте, когда сеанс подключен. Однако в случае ленивой страtagsи загрузки ленивая загрузка помеченного объекта не извлекает данные, если сеанс отключен (после оператора session.close() ). Все, что может быть сделано с помощью hibernate proxy. Стремительная страtagsя позволяет сохранять данные после закрытия сеанса.

По умолчанию для всех объектов коллекции и карты правило выборки – FetchType.LAZY а для других экземпляров – политика FetchType.EAGER .
@OneToMany @ManyToMany отношения @OneToMany и @ManyToMany не @ManyToMany связанные объекты (сбор и карту) неявно, но операция поиска каскадируется через поле в @OneToOne и @ManyToOne .

(любезность: – objectdbcom)

По моим сведениям, оба типа выборки зависят от вашего требования.

FetchType.LAZY по требованию (т.е. когда нам нужны данные).

FetchType.EAGER является немедленным (т. FetchType.EAGER До того, как наше требование приходит, мы без необходимости извлекаем запись)

Из Джавадока :

Страtagsя EAGER является обязательным требованием для среды выполнения поставщика непрерывности, которую данные должны получать с нетерпением. Страtagsя LAZY – это намек на время выполнения провайдера настойчивости, при котором данные должны извлекаться лениво при первом доступе.

Например, нетерпеливый более активен, чем ленив. «Ленивый» происходит только при первом использовании (если провайдер принимает подсказку), тогда как с нетерпеливыми вещами (может) получить предварительную выборку.

И FetchType.LAZY и FetchType.EAGER используются для определения плана выборки по умолчанию .

К сожалению, вы можете переопределить план выборки по умолчанию для получения LAZY. Выбор EAGER менее гибкий и может привести к многочисленным проблемам производительности .

Мой совет заключается в том, чтобы ограничить желание создавать ассоциации EAGER, потому что выборка – это ответственность за время запроса. Поэтому все ваши запросы должны использовать директиву fetch, чтобы получить только то, что необходимо для текущего бизнес-кейса.

Тип Lazy Fetch по умолчанию выбран Hibernate, если вы явно не указали тип Eager Fetch. Чтобы быть более точным и кратким, разница может быть указана ниже.

FetchType.LAZY = Это не загружает отношения, если вы не вызываете его с помощью метода getter.

FetchType.EAGER = Здесь загружаются все отношения.

Плюсы и минусы этих двух типов выборки.

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 listBooks=new ArrayList(); public List getListBooks() { return listBooks; } public void setListBooks(List 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(); } } } 

Проверьте метод retrieve () Main.java. Когда мы получим Subject, то его коллекция listBooks , аннотированная с @OneToMany , будет загружена лениво. Но, с другой стороны, связанная с книгами ассоциация объекта коллекции, аннотированная с помощью @ManyToOne , загружается с @ManyToOne уклоном (по [default][1] для @ManyToOne , fetchType=EAGER ). Мы можем изменить поведение, поместив fetchType.EAGER в @OneToMany Subject.java или fetchType.LAZY в @ManyToOne в Books.java.

public enum FetchType extends java.lang.Enum Определяет страtagsи для извлечения данных из базы данных. Страtagsя EAGER является обязательным требованием для среды выполнения поставщика непрерывности, которую данные должны получать с нетерпением. Страtagsя LAZY – это намек на время выполнения провайдера настойчивости, при котором данные должны извлекаться лениво при первом доступе. Реализации разрешено охотно извлекать данные, для которых указана страtagsя LAZY. Пример: @Basic (fetch = LAZY) protected String getName () {return name; }

Источник

@ drop-shadow, если вы используете Hibernate, вы можете вызвать Hibernate.initialize() когда вы вызываете метод getStudents() :

 Public class UniversityDaoImpl extends GenericDaoHibernate 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; } //... } 

LAZY: он извлекает дочерние объекты лениво, т. Е. Во время выборки родительского объекта он просто извлекает прокси (созданный cglib или любой другой утилитой) дочерних объектов и когда вы обращаетесь к любому свойству дочернего объекта, тогда он фактически извлекается с помощью спящего режима.

EAGER: он выбирает дочерние объекты вместе с родителем.

Для лучшего понимания обратитесь к документации Jboss или вы можете использовать hibernate.show_sql=true для своего приложения и проверить запросы, выданные спящим режимом.

  • В чем разница между @JoinColumn и mappedBy при использовании ассоциации JPA @OneToMany
  • NHibernate vs LINQ to SQL
  • org.hibernate.MappingException: Не удалось определить тип для: java.util.List, at table: College, для столбцов:
  • Нарушение спящего режима с помощью orphanRemoval
  • Нужны ли мне элементы в файле persistence.xml?
  • Bypass GeneratedValue в спящем режиме (данные объединить не в db?)
  • Что используется session.flush () в Hibernate
  • Бесконечная recursion с выпуском Jackson JSON и Hibernate JPA
  • Перечисление карты в JPA с фиксированными значениями?
  • mappedBy ссылается на неизвестное свойство целевого объекта
  • Что называется ссылочным именем ColumnName, используемым в JPA?
  • Давайте будем гением компьютера.