Hibernate - выборка стратегий

Hibernate - примеры стратегий выбора

Hibernate имеет несколько стратегий извлечения для оптимизации сгенерированного оператора Hibernate select, чтобы он мог быть максимально эффективным. Стратегия выборки объявляется в отношении сопоставления, чтобы определить, как Hibernate извлекает связанные коллекции и сущности.

Выбор стратегий

Есть четыре стратегии извлечения

1. fetch- «join» = Отключить отложенную загрузку, всегда загружать все коллекции и объекты.
2. fetch- «select» (по умолчанию) = Ленивая загрузка всех коллекций и сущностей.
3. batch-size = "N" = выборка до "N" коллекций или объектов,Not record.
4. fetch- «subselect» = сгруппировать свою коллекцию в оператор sub select.

Для подробного объяснения вы можете проверитьHibernate documentation.

Извлечение примеров стратегий

Вот пример отношения «один ко многим» для демонстрации выборочных стратегий. Акции принадлежат многим фондовым ежедневным записям.

Пример объявления стратегий выборки в XML-файле

...

    
        
            
                
            
            
        
    

Пример объявления стратегии выборки в аннотации

...
@Entity
@Table(name = "stock", catalog = "example")
public class Stock implements Serializable{
...
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "stock")
    @Cascade(CascadeType.ALL)
    @Fetch(FetchMode.SELECT)
        @BatchSize(size = 10)
    public Set getStockDailyRecords() {
        return this.stockDailyRecords;
    }
...
}

Давайте рассмотрим, как стратегии выборки влияют на сгенерированный оператор Hibernate.

1. fetch = ”select” или @Fetch (FetchMode.SELECT)

Это стратегия получения по умолчанию. это включало отложенную загрузку всех связанных с ним коллекций. Давайте посмотрим на пример ...

//call select from stock
Stock stock = (Stock)session.get(Stock.class, 114);
Set sets = stock.getStockDailyRecords();

//call select from stock_daily_record
for ( Iterator iter = sets.iterator();iter.hasNext(); ) {
      StockDailyRecord sdr = (StockDailyRecord) iter.next();
      System.out.println(sdr.getDailyRecordId());
      System.out.println(sdr.getDate());
}

Выход

Hibernate:
    select ...from example.stock
    where stock0_.STOCK_ID=?

Hibernate:
    select ...from example.stock_daily_record
    where stockdaily0_.STOCK_ID=?

Hibernate сгенерировал два оператора выбора

1. Оператор Select для получения записей Stock -session.get(Stock.class, 114)
2. Выберите связанные коллекции -sets.iterator()

2. fetch = ”join” или @Fetch (FetchMode.JOIN)

Стратегия извлечения «присоединиться» отключит отложенную загрузку всех связанных с ним коллекций. Давайте посмотрим на пример ...

//call select from stock and stock_daily_record
Stock stock = (Stock)session.get(Stock.class, 114);
Set sets = stock.getStockDailyRecords();

//no extra select
for ( Iterator iter = sets.iterator();iter.hasNext(); ) {
      StockDailyRecord sdr = (StockDailyRecord) iter.next();
      System.out.println(sdr.getDailyRecordId());
      System.out.println(sdr.getDate());
}

Выход

Hibernate:
    select ...
    from
        example.stock stock0_
    left outer join
        example.stock_daily_record stockdaily1_
            on stock0_.STOCK_ID=stockdaily1_.STOCK_ID
    where
        stock0_.STOCK_ID=?

Hibernate сгенерировал только один оператор select, он извлекает все связанные с ним коллекции при инициализации Stock. -session.get(Stock.class, 114)

1. Выберите оператор для извлечения фондовых записей и внешнего объединения его связанных коллекций.

3. batch-size = ”10 ″ или @BatchSize (size = 10)

Эта стратегия извлечения "размера партии" всегда недопонимается многими разработчиками Hibernate. Давайте посмотрим на концепциюmisunderstand здесь ...

Stock stock = (Stock)session.get(Stock.class, 114);
Set sets = stock.getStockDailyRecords();

for ( Iterator iter = sets.iterator();iter.hasNext(); ) {
      StockDailyRecord sdr = (StockDailyRecord) iter.next();
      System.out.println(sdr.getDailyRecordId());
      System.out.println(sdr.getDate());
}

Каков ваш ожидаемый результат, это 10 записей из коллекции на выборку? Смотрите вывод
Output

Hibernate:
    select ...from example.stock
    where stock0_.STOCK_ID=?

Hibernate:
    select ...from example.stock_daily_record
    where stockdaily0_.STOCK_ID=?

Размер пакета здесь ничего не сделал, дело не в том, как работает размер пакета. Смотрите это утверждение.

Стратегия выборки в пакетном режиме не определяет, сколько записей в коллекциях загружено. Вместо этого он определяет, сколько коллекций должно быть загружено.

- Повторите N раз, пока вы не запомните это утверждение -

Другой пример

Давайте посмотрим на другой пример, вы хотите распечатать все записи о запасах и связанные с ними ежедневные записи (коллекции) по одному.

List list = session.createQuery("from Stock").list();

for(Stock stock : list){

    Set sets = stock.getStockDailyRecords();

    for ( Iterator iter = sets.iterator();iter.hasNext(); ) {
            StockDailyRecord sdr = (StockDailyRecord) iter.next();
            System.out.println(sdr.getDailyRecordId());
            System.out.println(sdr.getDate());
    }
}
Нет стратегии выборки по размеру партии

Выход

Hibernate:
    select ...
    from example.stock stock0_

Hibernate:
    select ...
    from example.stock_daily_record stockdaily0_
    where stockdaily0_.STOCK_ID=?

Hibernate:
    select ...
    from example.stock_daily_record stockdaily0_
    where stockdaily0_.STOCK_ID=?

Keep repeat the select statements....depend how many stock records in your table.

Если в базе данных имеется 20 записей о запасах, стратегии выборки по умолчанию в Hibernate сгенерируют 20 + 1 операторов выбора и попадут в базу данных.

1. Оператор Select для получения всех записей акций.
2. Выберите соответствующую коллекцию
3. Выберите соответствующую коллекцию
4. Выберите соответствующую коллекцию
….
21. Выберите связанную коллекцию

Сгенерированные запросы неэффективны и вызвали серьезную проблему с производительностью.

Включил стратегию извлечения batch-size = ’10 ’

Давайте посмотрим на другой пример с включенным batch-size = ’10 ’.
Output

Hibernate:
    select ...
    from example.stock stock0_

Hibernate:
    select ...
    from example.stock_daily_record stockdaily0_
    where
        stockdaily0_.STOCK_ID in (
            ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
        )

Теперь Hibernate будет выполнять выборку коллекций с помощью оператора selectin. Если у вас есть 20 фондовых записей, он сгенерирует 3 выбранных отчета.

1. Оператор Select для получения всех записей акций.
2. Оператор Select In для выборки связанных коллекций (10 коллекций за раз)
3. Выберите В операторе, чтобы получать связанные коллекции (следующие 10 коллекций за раз)

С включенным размером пакета это упрощает операторы выбора с 21 оператора выбора до 3 операторов выбора.

4. fetch = ”subselect” или @Fetch (FetchMode.SUBSELECT)

Эта стратегия выборки включает все связанные коллекции в операторе sub select. Давайте посмотрим на тот же запрос снова ..

List list = session.createQuery("from Stock").list();

for(Stock stock : list){

    Set sets = stock.getStockDailyRecords();

    for ( Iterator iter = sets.iterator();iter.hasNext(); ) {
            StockDailyRecord sdr = (StockDailyRecord) iter.next();
            System.out.println(sdr.getDailyRecordId());
            System.out.println(sdr.getDate());
    }
}

Выход

Hibernate:
    select ...
    from example.stock stock0_

Hibernate:
    select ...
    from
        example.stock_daily_record stockdaily0_
    where
        stockdaily0_.STOCK_ID in (
            select
                stock0_.STOCK_ID
            from
                example.stock stock0_
        )

При включенном «subselect» будут созданы два оператора выбора.

1. Оператор Select для получения всех записей акций.
2. Выделите все связанные коллекции в запросе дополнительного выбора.

Заключение

Стратегии извлечения очень гибки и очень важны для оптимизации запроса Hibernate, но если вы используете его не в том месте, это будет полным провалом.