2009-12-10 13 views
5

Ich möchte Hibernate HQL-Abfragen "trockenlaufen lassen". Das würde ich gerne wissen, was tatsächliche SQL-Abfragen Hibernate von bestimmten HQL-Abfrage ausführen wird, ohne die HQL-Abfrage tatsächlich gegen echte Datenbank auszuführen.Hibernate und trocken laufende HQL-Abfragen statisch

Ich habe Zugriff auf Hibernate Mapping für Tabellen, die HQL-Abfrage Zeichenfolge, die dialect für meine Datenbank. Ich habe auch Zugriff auf die Datenbank, wenn dies erforderlich ist.

Nun, wie kann ich alle SQL-Abfragen herausfinden, die Hibernate von meinem HQL erzeugen kann, ohne die Abfrage tatsächlich gegen irgendeine Datenbank auszuführen? Gibt es dafür Werkzeuge?

Beachten Sie, dass viele SQL-Abfragen aus einer HQL-Abfrage generiert werden können und die Menge der generierten SQL-Abfragen basierend auf dem Inhalt der Datenbank abweichen kann.

Ich frage nicht, wie Sie SQL-Abfragen protokollieren, während die HQL-Abfrage ausgeführt wird.

Edit: Ich habe nichts dagegen, eine Verbindung zur Datenbank, um einige Metadaten zu holen, ich möchte nur keine Abfragen ausführen.

Edit: Ich weiß auch, welche Grenzen und Offsets für die Abfrage gelten. Ich habe auch die tatsächlichen Parameter, die an Abfrage gebunden werden.

Antwort

5

Die kurze Antwort ist "Sie können nicht". Die lange Antwort ist unten.

Es gibt zwei Ansätze können Sie nehmen:

A) Schauen Sie in HQLQueryPlan class, insbesondere seine getSqlStrings() method. Es wird Ihnen nicht die genaue SQL, weil weitere Vorverarbeitung beteiligt ist, bevor Abfrage tatsächlich ausgeführt wird (Parameter sind gebunden, Limit/Offset angewendet werden, etc ...) aber es kann nahe genug sein, was Sie wollen.

Die Sache zu beachten ist, dass Sie eine tatsächliche SessionFactory Instanz benötigen, um HQLQueryPlan zu konstruieren, was bedeutet, dass Sie nicht ohne "Verbindung mit einer Datenbank" tun können. Sie können jedoch die In-Memory-Datenbank (SqlLite und ähnliche) verwenden und Hibernate automatisch das erforderliche Schema dafür erstellen lassen.

B) Beginnen Sie mit ASTQueryTranslatorFactory und steigen Sie in AST/ANTLR-Wahnsinn. Theoretisch ist es vielleicht möglich, einen Parser zu hacken, der funktioniert, ohne auf Metadaten angewiesen zu sein, aber ich habe es am schwierigsten, mir vorzustellen, was ich versuche, damit es sich lohnt. Vielleicht kannst du das klären? Dort hat einen besseren Ansatz zu sein.

2

Update: für eine Offline, Dry-Run von einigen HQL, mit HQLQueryPlan direkt ist ein guter Ansatz. Wenn Sie jede Abfrage in der App während der Ausführung abfangen und die SQL-Anweisung aufzeichnen möchten, müssen Sie Proxies und Reflektionen wie unten beschrieben verwenden.

Werfen Sie einen Blick auf this answer für Kriterien Abfragen.

Für HQL ist es das gleiche Konzept - Sie müssen in Hibernate-Implementierungsklassen umwandeln und/oder auf private Mitglieder zugreifen, es ist also keine unterstützte Methode, aber es funktioniert mit den 3.2-3.3-Versionen von Hibernate. Hier ist der Code ist die Abfrage von HQL zuzugreifen (Abfrage ist das Objekt zurück von session.createQuery (hql_string):

Field f = AbstractQueryImpl.class.getDeclaredField("session"); 
f.setAccessible(true); 
SessionImpl sessionImpl = (SessionImpl) f.get(query); 
Method m = AbstractSessionImpl.class.getDeclaredMethod("getHQLQueryPlan", new Class[] { String.class, boolean.class }); 
m.setAccessible(true); 
HQLQueryPlan plan = (HQLQueryPlan) m.invoke(sessionImpl, new Object[] { query.getQueryString(), Boolean.FALSE }); 
for (int i = 0; i < plan.getSqlStrings().length; ++i) { 
    sql += plan.getSqlStrings()[i]; 
} 

ich all das in einem try/catch wickeln würde, so dass Sie mit der Abfrage weitergehen können wenn die Protokollierung nicht funktioniert.

Es ist möglich, Ihre Sitzung zu übertragen und dann Ihre Abfragen zu übernehmen, sodass Sie die SQL und die Parameter jeder Abfrage (hql, sql, criteria) vor der Ausführung protokollieren können, ohne dass der Code, der die Abfrage erstellt, ausgeführt werden muss (solange die erste Sitzung aus dem von Ihnen kontrollierten Code abgerufen wird).

+0

All diese Unordnung mit Reflexion ist völlig unnötig. 'HQLQueryPlan' hat einen öffentlichen Konstruktor; Sie müssen Ihre Sitzungsfactory nur auf 'SessionFactoryImplementor' übertragen. – ChssPly76

+0

Stimmt, und nachdem er seine Frage erneut gelesen hat, ist das wahrscheinlich alles, was er braucht. Ich habe die Situation angesprochen, in der Sie die HQL/SQL für jede in Ihrer Anwendung ausgeführte Abfrage in Echtzeit erfassen wollen - ohne jede Klasse in der Anwendung ändern zu müssen, die eine Abfrage ausführt. Da ich keine Löschberechtigung habe, habe ich eine Zeile zur Klärung hinzugefügt. –

+0

Fair genug; Wenn Sie jedoch nur SQL erfassen möchten, ist es wahrscheinlich einfacher (und viel wahrscheinlicher, Hibernate-Updates zu überleben), einen einfachen Appender zu schreiben und an 'org.hibernate.SQL' anzuhängen :-) – ChssPly76