Hibernate eager-loading (fetch alle Eigenschaften funktioniert nicht)
Grundsätzlich möchte ich gerne-load-Eigenschaften. Ich habe die folgende HQL-query:
SELECT u.id AS id, u.name AS text, u AS obj FROM User AS u fetch all properties
Ich würde erwarten, dass dieses zum ausführen einer Abfrage nur. Stattdessen bekam ich N+1 Abfragen.
Code ist der folgende:
Query q = mySession.createQuery(
"SELECT u.id AS id, u.name AS text, u AS obj FROM User AS u fetch all properties")
.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
for (Iterator i = q.iterate(); i.hasNext();) {
Object line = i.next();
System.out.println(line);
}
Die Ausgabe die ich bekomme (mit hibernate.show_sql
eingestellt true
) ist:
Hibernate: select user0_.id as col_0_0_, user0_.name as col_1_0_, user0_.id as col_2_0_ from user user0_
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.location as location0_0_ from user user0_ where user0_.id=?
{id=1, obj=User@b6548 [id='1' name='John' ], text=John}
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.location as location0_0_ from user user0_ where user0_.id=?
{id=2, obj=User@4865ce [id='2' name='Arnold' ], text=Arnold}
Ps: Die situation ist genau das gleiche, ohne Transformatoren.
Edit:
Der Datei mit den entity-mappings:
<hibernate-mapping>
<class name="User" table="user">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name"/>
<property name="location"/>
<map name="customPrices" table="custprice">
<key column="user"/>
<map-key-many-to-many column="product" class="Product"/>
<element column="price" type="double"/>
</map>
</class>
<class name="Product" table="product">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name"/>
<property name="listprice"/>
</class>
</hibernate-mapping>
Habe ich versucht, indem lazy="false"
auf die Klasse und den einzelnen Eigenschaften. Kein Unterschied.
Meine Konfiguration Datei:
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:mysql://192.168.0.203/hibtest</property>
<property name="connection.username">hibtest</property>
<property name="connection.password">hibb345</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
<property name="current_session_context_class">thread</property>
<property name="hibernate.show_sql">true</property>
<mapping resource="combined.hbm.xml" />
</session-factory>
</hibernate-configuration>
Edit2:
Sogar der folgende code führt zu N+1 Abfrage. Obwohl ich nur Holen Sie das ID-Feld, welches laut Dokumentation sollte nicht dazu führen, dass Objekte geladen werden.
for (Iterator i = q.iterate(); i.hasNext();) {
Object line = i.next();
User u = (User)((Map)line).get("obj");
System.out.println(u.getId());
}
- bitte fügen Sie Ihre hibernate-mapping. Es scheint, wie Sie Position Vereins ist träge geladen.
- Was genau wollen Sie erreichen mit dieser Abfrage? Warum müssen Sie angeben
id
undname
getrennt? - Harel habe ich noch die config-Dateien auf die Frage.
- Die Ergebnisse sind genau das, was ich erwarte. Nur die Art Ruhezustand holt das Ergebnis ist unrealistisch. Auch wenn ich explizit hinzufügen
fetch all properties
. - Gibt es einen bestimmten Grund, warum du: 1. die Verwendung von iterate() anstelle von list()? 2. wählen Sie einzelne Eigenschaften zusammen mit der Hauptsache?
- Die Ergebnisse sind gefüttert, um eine andere API. Aber ja: mit
.list().interator()
statt.interate()
Ursachen eager loading. Möchten Sie möglicherweise in diesem post als Antwort zu. - Nicht sehr intuitiv Verhalten. Macht mich Frage mich, wie viele Landminen wie diese Lüge in den Ruhezustand... - Harel Bitte schreiben Sie eine kurze Antwort, damit ich Sie akzeptieren kann 🙂
Du musst angemeldet sein, um einen Kommentar abzugeben.
War das problem mit
.iterate()
. Nach Hibernate-API-docs:Dies ist eine spezielle Funktion verwendet werden, wenn wir erwarten, dass die resultierenden Objekte werden bereits zwischengespeichert. Sie werden (lazy) geladen, wenn auf Sie zugegriffen wird.
Also für den Allgemeinen Gebrauch, um einen iterator auf das Ergebnis einer Abfrage, die Sie verwenden sollten
.list().iterate()
.Dank für Eran Harel für die Hilfe.
In der Essenz, die Ursache des Problems ist ein Versuch, zu integrieren, und das Ergebnis der transformation von Logik in einer Abfrage.
Ich denke, es wäre besser, um eine einfache HQL-Abfrage und wenden Sie dann Ihre spezifische Ergebnis transformationslogik in einem benutzerdefinierten
ResultTransformer
so etwas wie dieses:.iterate()
- scheinbar zwingt es einige superlazy - Modus über alle anderen Einstellungen..list().interator()
statt. - Neben der Tatsache, dass der name der Funktion vorschlagen, dieses spezielle Verhalten in den ersten Platz.Sieht aus wie es nicht abrufen kann, der obj in einer einzigen Abfrage mit getrennten Spalten.
Da Sie die gleichen Werte, die vom Benutzer für die anderen Spalten, im Beispiel von @axtavt scheint die beste Lösung.
.list().interator()
verwendet werden.