Разница между ленивым и стремящимся к настойчивости Java?

StackOverflow https://stackoverflow.com/questions/2990799

Вопрос

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

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

Это было полезно?

Решение

Иногда у вас есть две сущности, и между ними есть отношения. Например, у вас может быть сущность, называемая University и другая сущность вызвала Student И в университете может быть много студентов:

У организации университета могут быть некоторые основные свойства, такие как удостоверение личности, имя, адрес и т. Д., А также собственность сбора, называемую студентами, которые возвращают список студентов для данного университета:

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 загружает для вас свои идентификаторы, имени и адреса. Но у вас есть два варианта того, как студенты должны быть загружены:

  1. Загружать его вместе с остальными полей (т.е. с нетерпением), или
  2. Чтобы загрузить его по требованию (т.е. лениво), когда вы звоните в университет getStudents() метод

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

Вот пример, где 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 явно отмечено, чтобы быть лениво загруженным:

@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) Так что для ваших ленивых коллекций, бетонные типы не ArrayList а также HashSet, но PersistentSet а также PersistentList (или же PersistentBag)

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

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

(Предоставлено:- ObjectDbcom)

Согласно моим знаниям оба типа извлечения зависит от ваших требований.

FetchType.LAZY по требованию (т. Е. Когда мы требовали данных).

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

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

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

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

От Javadoc:

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

Например, стремитель более активен, чем ленивый. Lazy случается только при первом использовании (если поставщик берет подсказку), в то время как с нетерпеливыми вещами (может) предварительно извлечены.

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

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

        }

Субъект. Ява

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

    }

Проверьте метод retrieve () main.java. Когда мы получаем тему, затем его коллекция списки, аннотирован с @OneToMany, будет лениво загружаться. Но, с другой стороны, ассоциация коллекции, связанная с книгами предмет, аннотирован с @ManyToOne, загружается надо ( [default][1] за @ManyToOne, fetchType=EAGER) Мы можем изменить поведение, поместив gtchtype.eager на @OneToMany Субъект. @ManyToOne В книгах. Ява.

public enum fetchtype расширяет java.lang.enum определяет стратегии для извлечения данных из базы данных. Стремление к стратегии - это требование о времени выполнения поставщика настойчивости, которое данные должны быть с нетерпением. Ленивая стратегия является намеком на постоянную работу поставщика постоянств, что данные должны быть лениво извлечены при первом обращении. Реализация разрешена для склонного извлечения данных, для которых была указана ленивая стратегия. Пример: @basic (fetch = lazy) защищенная string getName () {return name; }

Источник

Я хочу добавить эту записку к тому, что «Кёнг Хван Мин» сказал выше.

Предположим, вы используете Spring Rest с этим простым архитектором:

Контроллер <--> сервис <--> Репозиторий

И вы хотите вернуть некоторые данные на фронт, если вы используете FetchType.LAZY, вы получите исключение после возвращения данных в метод контроллера, так как сеанс закрыт в службе, поэтому JSON Mapper Object Не могу получить данные.

Существует три общих варианта для решения этой проблемы, зависит от дизайна, производительности и разработчика:

  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;
    }
    //...
}

Lazy: он извлекает дочерние сущности, т.е. во время извлечения родительской сущности, он просто получает прокси (созданный Cglib или любую другую утилиту) детских сущностей, и когда вы получаете доступ к какому -либо собственности дочернего сущности, он фактически получает Hibernate.

Эйгер: он приносит детские сущности вместе с родителем.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top