Diferença entre FetchType LAZY e EAGER na Java Persistence API?

Eu sou um novato em Java Persistence API e Hibernate.

Qual é a diferença entre FetchType.LAZY e FetchType.EAGER na Java Persistence API?

Às vezes você tem duas entidades e há uma relação entre elas. Por exemplo, você pode ter uma entidade chamada Universidade e outra entidade chamada Estudante.

A entidade da universidade pode ter algumas propriedades básicas, como id, nome, endereço, etc., bem como uma propriedade chamada students:

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

Agora, quando você carrega uma universidade do database, a JPA carrega seus campos id, nome e endereço para você. Mas você tem duas opções para os alunos: carregá-la junto com o resto dos campos (ou seja, ansiosamente) ou carregá-la sob demanda (ou seja, preguiçosamente) quando você chama o método getStudents () da universidade.

Quando uma universidade tem muitos alunos, não é eficiente carregar todos os seus alunos quando não são necessários. Portanto, em casos semelhantes, você pode declarar que deseja que os alunos sejam carregados quando realmente forem necessários. Isso é chamado de carregamento lento.

Basicamente,

 LAZY = fetch when needed EAGER = fetch immediately 

EAGER carregamento de collections significa que eles são buscados totalmente no momento em que seu pai é buscado. Portanto, se você tiver Course e tiver List , todos os alunos serão buscados no database no momento em que o Course for buscado.

LAZY outro lado, LAZY significa que o conteúdo da List é buscado somente quando você tenta acessá-los. Por exemplo, chamando course.getStudents().iterator() . Chamar qualquer método de access na List iniciará uma chamada para o database para recuperar os elementos. Isso é implementado criando um proxy em torno da List (ou Set ). Então, para suas collections preguiçosas, os tipos concretos não são ArrayList e HashSet , mas PersistentSet e PersistentList (ou PersistentBag )

Eu posso considerar o desempenho e a utilização da memory. Uma grande diferença é que a estratégia de busca EAGER permite usar objects de dados buscados sem session. Por quê?
Todos os dados são buscados quando os dados marcados são ansiosos no object quando a session é conectada. No entanto, no caso de uma estratégia de carregamento lento, o carregamento lento do object marcado não recuperará dados se a session for desconectada (após a instrução session.close() ). Tudo o que pode ser feito pelo proxy de hibernação. A ansiosa estratégia permite que os dados continuem disponíveis após a conclusão da session.

Por padrão, para todos os objects de coleção e mapa, a regra de busca é FetchType.LAZY e, para outras instâncias, segue a política FetchType.EAGER .
Em resumo, as relações @ManyToMany e @ManyToMany não buscam os objects relacionados (coleção e mapa) de forma implícita, mas a operação de recuperação é colocada em cascata através do campo em @OneToOne e @OneToOne .

(cortesia: – objectdbcom)

De acordo com meu conhecimento, o tipo de busca depende da sua necessidade.

FetchType.LAZY está sob demanda (ou seja, quando solicitamos os dados).

FetchType.EAGER é imediato (ou seja, antes que nossa exigência chegue, estamos buscando desnecessariamente o registro)

Do Javadoc :

A estratégia EAGER é um requisito no tempo de execução do provedor de persistência que os dados devem ser avidamente buscados. A estratégia LAZY é uma dica para o tempo de execução do provedor de persistência que os dados devem ser buscados de forma preguiçosa quando forem acessados ​​pela primeira vez.

Por exemplo, ansioso é mais proativo do que preguiçoso. Preguiçoso só acontece no primeiro uso (se o provedor aceitar a dica), enquanto que com coisas ansiosas (pode) ser pré-buscado.

Tanto FetchType.LAZY quanto FetchType.EAGER são usados ​​para definir o plano de FetchType.EAGER padrão .

Infelizmente, você só pode sobrescrever o plano de busca padrão para a busca do LAZY. A busca do EAGER é menos flexível e pode levar a muitos problemas de desempenho .

Meu conselho é restringir o desejo de tornar suas associações EAGER, pois buscar é uma responsabilidade de tempo de consulta. Portanto, todas as suas consultas devem usar a diretiva de busca para recuperar apenas o que é necessário para o caso de negócios atual.

O tipo Lazy Fetch é selecionado por padrão pelo Hibernate, a menos que você Eager explicitamente o tipo Eager Fetch. Para ser mais preciso e conciso, a diferença pode ser declarada como abaixo.

FetchType.LAZY = Isso não carrega os relacionamentos, a menos que você os invoque por meio do método getter.

FetchType.EAGER = Isso carrega todos os relacionamentos.

Prós e Contras desses dois tipos de busca.

Lazy initialization melhora o desempenho, evitando cálculos desnecessários e reduzindo os requisitos de memory.

Eager initialization rápida requer mais consumo de memory e a velocidade de processamento é lenta.

Dito isto, depende da situação em que uma dessas inicializações possa ser usada.

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(); } } } 

Verifique o método retrieve () de Main.java. Quando chegarmos a Subject, a lista de colecções Books , anotada com @OneToMany , será carregada preguiçosamente. Mas, por outro lado, Books relacionou associação de assunto de coleção, anotado com @ManyToOne, carrega eargerly (por [default][1] para fetchType=EAGER , fetchType=EAGER ). Podemos mudar o comportamento colocando fetchType.EAGER em @OneToMany Subject.java ou fetchType.LAZY em @ManyToOne em Books.java.

enum público FetchType estende java.lang.Enum Define estratégias para buscar dados do database. A estratégia EAGER é um requisito no tempo de execução do provedor de persistência que os dados devem ser avidamente buscados. A estratégia LAZY é uma dica para o tempo de execução do provedor de persistência que os dados devem ser buscados de forma preguiçosa quando forem acessados ​​pela primeira vez. A implementação tem permissão para buscar ansiosamente dados para os quais a dica da estratégia LAZY foi especificada. Exemplo: @Basic (fetch = LAZY) protegido String getName () {return name; }

Fonte

@ drop-shadow se você estiver usando o Hibernate, você pode chamar o Hibernate.initialize() quando invocar o método 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: Ele busca as entidades filhas preguiçosamente, ou seja, no momento da busca da entidade pai, ele busca apenas o proxy (criado pelo cglib ou qualquer outro utilitário) das entidades filhas e quando você acessa qualquer propriedade da entidade filha, ele é buscado pelo hibernate.

EAGER: busca as entidades da criança junto com os pais.

Para entender melhor, vá para a documentação do Jboss ou você pode usar hibernate.show_sql=true para seu aplicativo e verificar as consultas emitidas pelo hibernate.