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 SetgetStockDailyRecords() { 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 раз, пока вы не запомните это утверждение -
Другой пример
Давайте посмотрим на другой пример, вы хотите распечатать все записи о запасах и связанные с ними ежедневные записи (коллекции) по одному.
Listlist = 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. Давайте посмотрим на тот же запрос снова ..
Listlist = 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, но если вы используете его не в том месте, это будет полным провалом.