2009-09-23 6 views
1

Java Persistence avec Hibernate montre beaucoup d'exemples de chercher avec empressement associés entités, telles que:Hibernate: Comment chercher avec impatience des entités non associées?

  • Ajout @ org.hibernate.annotations.BatchSize à la classe associée
  • Ajout @ org.hibernate .annotations.Fetch au champ qui fait référence à la classe associée
  • en utilisant le mot-clé « chercher » dans la requête HQL, etc ...

Cependant, dans mon cas, je traite un processus lent qui est responsable de la construction d'associations à la classe d'intérêt de l'entité. Cela signifie que - au moment de l'exécution - je ne peux pas interroger une entité et lui demander d'aller chercher toutes les instances associées de l'autre entité avec impatience car aucune association n'existe.

En d'autres termes, le processus ressemble à quelque chose comme ceci:

public class InitConfig { 

    private final SessionFactory sessionFactory; 
    private final NodeManager nodeManager; 

    public void run() { 

     final Configuration config = new Configuration("NewConfiguration", new HashSet<Node>()); 
     for(String name : lotsOfNames) { 

      //Lots of these queries run slowly 
      final Node node = this.nodeManager.getNode(name); 
      config.addNode(node); 
     } 
     this.sessionFactory.getCurrentSession().save(config); 
    } 
} 

Le DAO lié (NodeManager) et l'entité (Node) lente interrogation ressembler à ceci:

public class NodeManager { 

    private final SessionFactory sessionFactory; 

    public Node getNode(String name) { 

     final Session db = this.sessionFactory.getCurrentSession(); 
     final Query query = db.createQuery("from NODE where NAME = :name"); 
     query.setString("name", name); 
     return (Node)query.uniqueResult(); 
    } 
} 

@Entity(name="NODE") 
public class Node { 

    @GeneratedValue(strategy=GenerationType.TABLE) 
    @Id @Column(name="ID") 
    private Long id; 

    private @Column(name="NAME", nullable=false, unique=true) String name; 

    //Other properties and associations... 
} 

Et enfin, l'entité créée par le lent processus en cours d'exécution:

@Entity(name="CONFIGURATION") 
public class Configuration { 

    @Id @GeneratedValue @Column(name="ID") 
    private Long id; 
    private @Column(name="NAME", nullable=false, unique=true) String name; 

    @ManyToMany 
    @JoinTable(
     name="CONFIGURATION_NODE", 
     [email protected](name="CONFIGURATION_ID", nullable=false), 
     [email protected](name="NODE_ID", nullable=false)) 
    private Set<Node> nodes = new HashSet<Node>(); 

    public void addNode(Node node) { 

     this.nodes.add(node); 
    } 
} 

Ma question est la suivante: Comment d o Je modifie la configuration Hibernate et/ou le code pour aller chercher de nombreuses instances de Node à la fois?

Suivez sur des questions serait:

  • est le 2 cache de niveau Hibernate approprié pour cela, et si oui - comment puis-je configurer?
  • Sinon, existe-t-il une autre fonctionnalité Hibernate qui peut être utilisée ici?

Il y a environ 100.000 nœuds au moment, donc je suis réticent à prendre l'approche force brute de l'interrogation chaque nœud et la mise en cache dans l'application quelque part, puisque ce ne serait pas l'échelle à un plus grand nombre de nœuds et il semble que cela dupliquerait les données entre l'application et les internes d'Hibernate (Session, cache de 2nd niveau, etc ...).

Répondre

2

Je ne suis pas 100% clair sur ce que vous essayez de faire ici ... Est-ce que Configuration.addNode() (ou une autre méthode que vous n'avez pas montrée) implique une logique métier?

Si ce n'est pas le cas, il est préférable d'exécuter plusieurs requêtes de mise à jour par lots pour associer vos nœuds à la configuration.

Si tel est le (ce qui signifie que vous devez charger et inspecter chaque nœud), vous pouvez:

  1. Divisez votre liste complète lotsOfNames en lots de, disons, 1000 noms (vous pouvez jouer avec ce numéro pour voir ce qui donne des performances optimales).
  2. Chargez le lot entier de noeuds à la fois via une requête avec la condition name IN(?).
  3. Ajoutez-les à votre configuration.
  4. Vider la session (et, éventuellement, valider/démarrer une nouvelle transaction).

Devrait être beaucoup plus rapide que vous ferez 1 requête au lieu de 1000 et le lot de vos insertions ensemble.

+0

Configuration.addNode() appelle simplement Configuration.nodes.add (Node). Il n'y a pas vraiment de logique métier, sauf qu'il peut y avoir des noms dans lotsOfNames qui n'ont pas de nœud correspondant. L'approche de requête de mise à jour par lots semble être une bonne idée. Cela fonctionnera-t-il encore si je transmets des noms de noeuds qui pourraient ne pas exister? –

+0

Oui, tout à fait. 'insérer dans CONFIGURATION_NODE (CONFIGURATION_ID, NODE_ID), sélectionnez: configurationId, ID de NODE où NAME dans (: nom)'. Vous aurez besoin de l'exécuter en tant que SQL natif et vous aurez toujours besoin de diviser votre grande liste en lots de 1000 ou plus (à moins que vous l'obteniez à partir d'une table pour commencer, auquel cas vous pouvez simplement vous y joindre dans cette requête) – ChssPly76

+0

Merci! L'utilisation de mises à jour par lots en SQL natif est beaucoup plus rapide que l'approche que j'utilisais auparavant. Je serais curieux de voir s'il existe une version HQL plus portable, mais cela fonctionne pour le moment. –

Questions connexes