Hibernate - exemples de stratégies de récupération
Hibernate a peu de stratégies d'extraction pour optimiser l'instruction select générée par Hibernate, afin qu'elle puisse être aussi efficace que possible. La stratégie d'extraction est déclarée dans la relation de mappage pour définir comment Hibernate récupère ses collections et entités associées.
Stratégies de récupération
Il existe quatre stratégies de récupération
1. fetch- “join” = Désactive le chargement différé, charge toujours toutes les collections et entités.
2. fetch- «select» (par défaut) = Charge différée toutes les collections et entités.
3. batch-size = "N" = Récupération de "N" collections ou entités,Not record.
4. fetch- "subselect" = Grouper sa collection en une instruction sub select.
Pour une explication détaillée, vous pouvez vérifier lesHibernate documentation.
Exemples de stratégies de récupération
Voici un exemple de "relation un-à-plusieurs" pour la démonstration des stratégies de récupération. Un stock appartient à de nombreux enregistrements quotidiens de stock.
Exemple de déclaration de stratégies de récupération dans un fichier XML
...
Exemple de déclaration de stratégies de récupération dans l'annotation
... @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; } ... }
Explorons comment les stratégies d'extraction affectent l'instruction SQL générée par Hibernate.
1. fetch = "select" ou @Fetch (FetchMode.SELECT)
Il s'agit de la stratégie de récupération par défaut. il a permis le chargement paresseux de toutes les collections associées. Voyons l'exemple…
//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()); }
Sortie
Hibernate: select ...from example.stock where stock0_.STOCK_ID=? Hibernate: select ...from example.stock_daily_record where stockdaily0_.STOCK_ID=?
Hibernate a généré deux instructions select
1. Sélectionnez instruction pour récupérer les enregistrements de stock -session.get(Stock.class, 114)
2. Sélectionnez ses collections associées -sets.iterator()
2. fetch = "join" ou @Fetch (FetchMode.JOIN)
La stratégie de récupération de «jointure» désactivera le chargement paresseux de toutes les collections associées. Voyons l'exemple…
//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()); }
Sortie
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 n'a généré qu'une seule instruction select, il récupère toutes ses collections associées lorsque le Stock est initialisé. -session.get(Stock.class, 114)
1. Sélectionnez l'instruction pour récupérer les enregistrements Stock et joindre à l'extérieur ses collections associées.
3. batch-size = ”10 ″ ou @BatchSize (taille = 10)
Cette stratégie de récupération de «taille de lot» est toujours mal comprise par de nombreux développeurs Hibernate. Voyons le conceptmisunderstand ici…
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()); }
Quel est votre résultat escompté, est-ce que 10 enregistrements per-fetch de la collection? Voir la sortie
Output
Hibernate: select ...from example.stock where stock0_.STOCK_ID=? Hibernate: select ...from example.stock_daily_record where stockdaily0_.STOCK_ID=?
La taille de lot n'a rien fait ici, ce n'est pas ainsi que fonctionne la taille de lot. Voir cette déclaration.
La stratégie d'extraction par taille de lot ne définit pas le nombre d'enregistrements à l'intérieur des collections qui sont chargés. Au lieu de cela, il définit le nombre de collections à charger.
- Répétez N fois jusqu'à ce que vous vous souveniez de cette déclaration -
Un autre exemple
Voyons un autre exemple, vous voulez imprimer tous les enregistrements de stock et ses enregistrements quotidiens de stock associés (collections) un par un.
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()); } }
Aucune stratégie d'extraction de taille de lot
Sortie
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.
Si vous avez 20 enregistrements de stock dans la base de données, les stratégies de récupération par défaut d'Hibernate généreront 20 + 1 instructions de sélection et frapperont la base de données.
1. Sélectionnez instruction pour récupérer tous les enregistrements Stock.
2. Sélectionnez sa collection associée
3. Sélectionnez sa collection associée
4. Sélectionnez sa collection associée
….
21. Sélectionnez sa collection associée
Les requêtes générées ne sont pas efficaces et ont causé un sérieux problème de performances.
Activation de la stratégie d'extraction batch-size = ’10 ’
Voyons un autre exemple avec batch-size = '10 'est activé.
Output
Hibernate: select ... from example.stock stock0_ Hibernate: select ... from example.stock_daily_record stockdaily0_ where stockdaily0_.STOCK_ID in ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
Désormais, Hibernate récupérera automatiquement les collections, avec une instruction selectin. Si vous avez 20 enregistrements de stock, il générera 3 relevés sélectionnés.
1. Sélectionnez instruction pour récupérer tous les enregistrements Stock.
2. Sélectionnez In instruction pour récupérer automatiquement ses collections associées (10 collections à la fois)
3. Sélectionnez l'instruction In pour extraire ses collections associées (10 prochaines collections à la fois)
Lorsque la taille de lot est activée, elle simplifie les instructions select de 21 instructions select à 3 instructions select.
4. fetch = "subselect" ou @Fetch (FetchMode.SUBSELECT)
Cette stratégie d'extraction permet d'activer toute sa collection associée dans une instruction de sous-sélection. Voyons à nouveau la même requête.
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()); } }
Sortie
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_ )
Lorsque la «sous-sélection» est activée, elle crée deux instructions de sélection.
1. Sélectionnez instruction pour récupérer tous les enregistrements Stock.
2. Sélectionnez toutes ses collections associées dans une requête de sous-sélection.
Conclusion
Les stratégies de récupération sont très flexibles et un ajustement très important pour optimiser la requête Hibernate, mais si vous l'utilisez au mauvais endroit, ce sera un désastre total.