1. Abfrage von Entitätsobjekten
Entitätsobjektabfrage ist die Grundlage für die HQL -Abfrage. Als Objektabfragesprache unterscheidet es sich während der Abfragemopien von SQL. Der Inhalt in der Abfragezeichenfolge sollte durch den Klassennamen und den Klassenattributnamen ersetzt werden. Diese Abfragemethode ist relativ einfach. Solange Sie SQL -Fähigkeiten haben, ist es sehr einfach, die HQL zu verwenden. Es gibt jedoch einige Probleme, die auf Beachtung geschätzt werden müssen, dh Abfragen und Erhalt von Daten ist nicht der Zweck, und was berücksichtigt werden muss, ist, wie effiziente Abfrageanweisungen geschrieben werden müssen, was im Mittelpunkt der Diskussion steht.
1.N+1 Problem
(1) Was ist das N+1 -Problem?
Als ich dieses Substantiv zum ersten Mal hörte, kann ich Zweifel haben. Ich habe noch nie von dem N+1 -Problem gehört. Also, was bedeutet es? N+1 bezieht sich auf N -Daten in einer Tabelle. Wenn Sie diese N -Daten erhalten, wird der Befehl n+1 sql generiert. Diese Operation heißt N+1. Hier bezieht sich 1 auf die Ausgabe einer Erklärung, die nach der ID -Liste gesucht wird, und n verweist auf die Ausgabe von N -SQL -Anweisungen auf der Grundlage auf ID, um verwandte Objekte zu laden. Diese Art von Abfrageoperation ist sehr ineffizient und wird häufig bei Iteratoren erzeugt. Das heißt, wenn wir die Abfrageergebnisse direkt in Iteratoren umwandeln, tritt dieses Problem wie folgt auf:
public void testQuery () {Session Session = null; try {session = hibernateUtils.getSession (); Sitzung.BeginTransaction (); /*** Es wird ein N+1 -Problem geben. Der sogenannte n+1 wert ist es, n+1 SQL-Anweisungen** 1: Ausgeben eine Anweisung, die die ID-Liste abfragt while (iter.hasnext ()) {student student = (student) iter.next (); System.out.println (student.getName ()); } Session.getTransaction (). commit (); } catch (Ausnahme e) {e.printstacktrace (); Session.Gettransaction (). Rollback (); } endlich {HibernateUtils.Closession (Sitzung); }}Der obige Abfragecode verursacht ein Problem mit einem N+1 -Problem, da die Abfrage als Iterator zurückgegeben wird, so dass eine SQL -Anweisung ausgestellt wird, wenn sie nicht einmal generiert wird. Dies hängt hauptsächlich vom Abfragemechanismus des Iterators ab, der Daten aus dem Cache abfragt. Wenn die Daten im Cache nicht vorhanden sind, werden die Daten zuerst in den Speicher konvertiert, sodass eine SQL -Abfrageanweisung zu diesem Zeitpunkt ausgegeben wird, sodass eine SQL -Anweisung jede Iteration generiert wird. Diese Schreibmethode ist tatsächlich ein Fehler und kann mit anderen Methoden zur Optimierung gelöst werden.
(2) N+1 Problem vermeiden
Das Problem von N+1 tritt aufgrund der unangemessenen Verwendung von ITERAT auf. Natürlich können andere Methoden verwendet werden, um dieses Problem von N+1 zu vermeiden. Hier ist eine Listenmethode. Der größte Unterschied zwischen Liste und Iterate besteht darin, dass die Liste Daten in den Cache steckt, aber den Cache nicht verwendet. Standardmäßig gibt die Liste jedes Mal SQL -Anweisungen aus. Vor der Verwendung der IT -IT können Sie die Liste verwenden, um die Daten in der Datenbank zu speichern, damit die ITREAT beim Zugriff auf die Daten aus dem Cache lesen kann, wodurch das Auftreten von N+1 -Problemen vermieden wird. Der Code ist wie folgt:
public void testQuery () {Session Session = null; try {session = hibernateUtils.getSession (); Sitzung.BeginTransaction (); List student = session.createquery ("From Student"). List (); System.out.println ("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Dann werden keine SQL -Anweisungen auf der Basis von ID ausgestellt, und die Daten im Cache werden direkt verwendet * * Iterate -Methode Wenn Daten im Cache vorhanden sind, können N+1 -Probleme auftreten * // Sie können den AS alias iterator iterator = session.createquery ("von student") verwenden (). System.out.println (student.getName ()); }}Das obige Beispiel vermeidet das N+1-Problem, da nach der Ausführung des Listenvorgangs die Daten im Sitzungscache (Cache der ersten Ebene) platziert werden. Bei der Verwendung von ITerate wird daher eine Anweisung ausgestellt, um die ID -Liste abzufragen, und dann werden die entsprechenden Daten gemäß der ID in den Cache geladen. Wenn Daten im Cache übereinstimmen, wird die auf der ID basierende SQL -Anweisungsabfrage nicht mehr ausgestellt, und die Daten im Cache werden direkt verwendet. Die ITREAT -Methode kann die Leistung verbessern, wenn Daten im Cache vorhanden sind, sonst treten Probleme auf.
2. Objektnavigationsabfrage
Die Objektnavigation bezieht sich auf das Erhalten von Daten aus einem anderen Objekt gemäß der Attributnavigation des Objekts in einem Objekt. Dies kann Abfrageanweisungen vereinfachen und Abfragemethoden optimieren. Wenn wir unseren üblichen Ideen folgen, können wir ein Objekt einer anderen Klasse umschreiben und schreiben, um die Funktionsweise eines anderen Objekts zu erhalten, das umständlich mehr ist, um die Anweisung der Objektnavigation zu vergleichen.
@SuppressWarnings ({"Deaktiviert", "rawtypes"}) public void testQuery () {Session Session = null; try {session = hibernateUtils.getSession (); Sitzung.BeginTransaction (); // Rückgabe der Ergebnis -Set -Attributliste, die Elementtyp- und Attributtypen in der Entitätsklasse sind dieselbe Liste der Schüler = Session für (iterator item = student.Iterator (); ite.hasnext ();) {Student obj = (student) ite.next (); System.out.println (obj.getName ()); } Session.getTransaction (). commit (); } catch (Ausnahme e) {e.printstacktrace (); Session.Gettransaction (). Rollback (); } endlich {HibernateUtils.Closession (Sitzung); }}Die Abfrageanweisung im obigen Beispiel verwendet die Objektnavigationsmethode. Die Abfrageanweisung ist die Informationsabfrage aus dem Schülerobjekt, aber die zu verglichenen Objektattribute stammen aus dem Namensattribut des Klassenobjekts. Zu diesem Zeitpunkt verbessert die Verwendung der Objektnavigation -Abfrage -Methode die Abfrageeffizienz erheblich und optimiert die Abfrageanweisung. Wenn es sich um eine gewöhnliche Abfragemethode handelte, kann eine große Anzahl von Verbindungsanweisungen generiert werden, was sehr kompliziert ist.
2. SQL Native Abfrage
Der native Abfragwert besteht darin, SQL -Anweisungen zu verwenden, um Daten abzufragen und zu erhalten, anstatt HQL -Anweisungen zu verwenden. Die Nutzungsmethode ist eigentlich sehr einfach, ähnlich wie HQL. Sie müssen nur die erstellige Methode zur Abfrage verwenden. Es ähnelt tatsächlich der Createquery -Methode von HQL. Der Code ist wie folgt:
public void testqeury () {Sitzung Session = null; try {session = hibernateUtils.getSession (); Sitzung.BeginTransaction (); Listlist = session.createSQLQuery ("aus t_student auswählen"). List (); für (iterator item = list.iterator (); ite.hasnext ();) {Object [] obj = (Object []) ite.Next (); System.out.println (obj [0]+","+obj [1]); } Session.getTransaction (). commit (); } catch (Ausnahme e) {e.printstacktrace (); Session.Gettransaction (). Rollback (); } endlich {HibernateUtils.Closession (Sitzung); }}Der obige Code verwendet die Methode createSQLQuery. Die Abfragezeichenfolge in der Methode ist eine SQL -Anweisung. Es implementiert die zugrunde liegende String -Abfragemethode. Der Unterschied besteht darin, dass HQL eine andere Verpackungsebene hat und die entsprechenden Dialektoptionen in hibernate.cfg.xml konfiguriert, um die Zuordnung zu vervollständigen.
3. Verbindungsabfrage
Verbindungsabfragen werden häufig in SQL verwendet, um eine Sammlung mehrerer Objekte zu erhalten. Unter ihnen sind die am häufigsten verwendeten inneren Join, linker Join, rechts Join usw., die sich auf die innere Join -Abfrage, die linke äußere Join -Abfrage und die rechte äußere Join -Abfrage beziehen. Der Inhalt, den sie während der Abfrage zurückgeben, ist das kartesische Produkt zwischen Entitäten, der Inhalt der Abfrage und einiger Inhalte der linken Tabelle, des Abfrageinhalts und einiger Inhalte der rechten Tabelle und der Abfragefunktion ist leistungsfähig. Die Verbindungsabfragemethode von HQL und die Verbindungsabfrage von SQL sind in Abfrageergebnissen gleich, aber es gibt geringfügige Unterschiede in Abfrageanweisungen.
1. innere Verbindung
Die Intrajoin -Abfrage von HQL kann mit der inneren Join -Anweisung oder der Anweisung angelegt werden, und das erhaltene Ergebnis ist kartesisches Produkt. Ähnlich wie bei der SQL-Intra-Connection-Abfrage ist die Join-Abfrage von HQL in zwei Typen unterteilt: explizit und implizit. Die angezeigte Abfrage bezieht sich auf das Keyword in der Abfrage -Zeichenfolge. Die implizite Abfrage muss nicht in die Zeichenfolge Join hinzufügen.
// innere Verbindung @SuppressWarnings ({"Unerrefiziert", "rawtypes"}) public void testQuery () {session session = null; try {session = hibernateUtils.getSession (); Sitzung.BeginTransaction (); // Rückgabe der Ergebnis -Set -Attributliste, die Elementtyp- und Attributtypen in der Entitätsklasse sind dieselbe Liste students = session für (iterator item = students.iterator (); ite.hasnext ();) {Object [] obj = (Object []) ite.Next (); System.out.println (OBJ [0]); } Session.getTransaction (). commit (); } catch (Ausnahme e) {e.printstacktrace (); Session.Gettransaction (). Rollback (); } endlich {HibernateUtils.Closession (Sitzung); }}
2. Externe Verbindung
Externe Verbindungen werden in die linke äußere Verbindung und die rechte Außenverbindungsabfrage unterteilt. Die Abfragemethoden sind ähnlich, das Abfrageergebnis ist jedoch unterschiedlich. Sie sind die gleichen wie die externe Verbindung von SQL in den Abfrageergebnissen. Der Unterschied ist die Schreibmethode. Der spezifische Code lautet wie folgt:
@SuppressWarnings ({"Deaktiviert", "rawtypes"}) public void testQuery () {session session = null; try {session = hibernateUtils.getSession (); Sitzung.BeginTransaction (); // Rückgabe der Ergebnis -Set -Attributliste, die Elementtyp- und Attributtypen in der Entitätsklasse sind dieselbe Liste students = session.createquery ("SELECT S.NAME, C.NAME AUSSCHLUSS AUSSCHLUSS BEI STUDENS LINKEN STECKLICH STECKENS CLASSS C"). LIST (); für (iterator item = students.iterator (); ite.hasnext ();) {Object [] obj = (Object []) ite.Next (); System.out.println (OBJ [0]); } Session.getTransaction (). commit (); } catch (Ausnahme e) {e.printstacktrace (); Session.Gettransaction (). Rollback (); } endlich {HibernateUtils.Closession (Sitzung); }}Der obige Code verwendet eine Anweisung für linke äußere Join -Abfrage. Die entsprechende rechte Außenverbindungs -Abfragemethode ähnelt dem linken äußeren Join. Konvertieren Sie einfach links nach rechts. Die Abfragendaten werden im Listenobjekt gespeichert und der Abfrageinhalt kann über die Liste erhalten werden.
4. Externe Namensfrage
External Named Query bezieht sich auf das Schreiben von Abfrageanweisungen in eine Zuordnungsdatei und die Verwendung des <query> -Tags, um HQL -Anweisungen in der Zuordnungsdatei zu definieren. Auf diese Weise können die definierten HQL -Anweisungen die Funktion der Funktionskonfiguration realisieren. Wenn es ein Problem gibt, müssen Sie nur die Konfiguration ändern. Wenn Sie diese SQL -Anweisung verwenden möchten, können Sie die Methode der Sitzung.GetNamedQuery () im Programm verwenden, um die HQL -Abfrage -Zeichenfolge abzurufen, wie im folgenden Beispiel gezeigt.
1. Externe Anweisung
Das folgende Beispiel zeigt die Anwendung externer Abfrageanweisungen, fügen Sie die <query> -Tag in der Zuordnungsdatei hinzu, fügen Sie das Tag -Attribut zum Tag hinzu und fügen Sie die Zeichenfolge zu <! [CDATA []]> hinzu, so dass der entsprechende Abfragezeichenfolge gemäß dem Namensattribut der Abfrage im Programm erhalten werden kann.
<? table="t_student"> <id name="id"> <generator//id> <property name="name"/> <property name="createTime"></property> <!-- Add a new Classes column to the Student on one side, and the column name should be the same as the List of Classes.hbm.xml --> <many-to-one name="classes" column="classesid"></many-to-one> </class> <query name = "quietudent"> <! ]]> </query> </hibernate-Mapping>
Die externe benannte Abfrage stellt die Anweisung Abfrage in die Zuordnungsdatei ein, sodass sie als öffentliche Abfrage -Zeichenfolge angesehen werden kann. Dies ist der Vorteil, damit andere Programmdateien erhalten und verwendet werden können. Darüber hinaus erhöht es die Bequemlichkeit der Änderung als öffentliche Zeichenfolge.
2. Programmanwendung
Nach der Definition externer Abfrageanweisungen müssen sie im Programm verwendet werden. HQL stellt die GetNamequery -Methode zur Verfügung, um die Anweisungszeichenfolge für externe Abfragen zu erhalten. Ein externer Cursorname muss dieser Methode hinzugefügt werden. HQL wird den entsprechenden SQL -Anweisungsblock basierend auf dem Cursornamen wie folgt abfragen:
// externe Namensabfrage @SuppressWarnings ({"Deaktiviert", "rawtypes"}) public void testQuery () {Session Session = null; try {session = hibernateUtils.getSession (); Sitzung.BeginTransaction (); List students = session.getNamedQuery ("quietudent"). SetParameter (0, 10) .List (); für (iterator item = student.ite.hasnext ();) {student obj = (student) ite.next (); System.out.println (obj.getName ()); } Session.getTransaction (). commit (); } catch (Ausnahme e) {e.printstacktrace (); Session.Gettransaction (). Rollback (); } endlich {HibernateUtils.Closession (Sitzung); }}