Hibernate - Exemples de stratégies de récupération

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 Set getStockDailyRecords() {
        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.

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

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

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.