2009-12-10 2 views
5

Hibernate HQL 쿼리를 "dry-run"하고 싶습니다. 실제 데이터베이스에 대해 HQL 쿼리를 실제로 실행하지 않고 Hibernate가 주어진 HQL 쿼리로부터 실행할 실제 SQL 쿼리를 알고 싶습니다.Hibernate와 dry-running HQL 쿼리는 정적으로

테이블에 대한 최대 절전 매핑, HQL 쿼리 문자열, 내 데이터베이스에 대한 dialect에 대한 액세스 권한이 있습니다. 데이터베이스가 필요한 경우에도 액세스 할 수 있습니다.

이제 Hibernate가 데이터베이스에 대한 쿼리를 실제로 실행하지 않고 HQL에서 생성 할 수있는 모든 SQL 쿼리를 어떻게 찾을 수 있습니까? 이것을위한 도구가 있습니까?

하나의 HQL 쿼리에서 많은 SQL 쿼리를 생성 할 수 있으며 생성 된 SQL 쿼리 집합은 데이터베이스의 내용에 따라 다를 수 있습니다.

HQL 쿼리가 실행되는 동안 SQL 쿼리를 기록하는 방법을 묻지 않습니다.

편집 : 메타 데이터를 가져 오기 위해 데이터베이스에 연결하는 데 신경 쓰지 않고 쿼리를 실행하고 싶습니다.

편집 : 또한 어떤 제한과 오프셋이 쿼리에 적용되는지 알고 있습니다. 또한 쿼리에 바인딩 할 실제 매개 변수가 있습니다.

답변

5

짧은 대답은 "할 수 없다"입니다. 긴 대답은 아래에 있습니다. 특히 그 getSqlStrings() method

A) HQLQueryPlan class로 봐 :

가 취할 수있는 두 가지 방법이 있습니다. 쿼리가 실제로 실행되기 전에 더 많은 전처리가 필요하기 때문에 (매개 변수가 바인딩되고, 제한/오프셋이 적용되는 등 ...) 사용자가 원하는만큼 충분히 근접 할 수 있기 때문에 정확한 SQL을 얻을 수 없습니다.

여기서 염두에 두어야 할 점은 HQLQueryPlan을 구성하기 위해 실제 SessionFactory 인스턴스가 필요하다는 것입니다. 즉, "데이터베이스에 연결하지 않고"수행 할 수 없습니다. 그러나, 메모리 내 데이터베이스 (SqlLite 등)를 사용하여 Hibernate가 필요한 스키마를 자동으로 생성하게 할 수 있습니다.

B) ASTQueryTranslatorFactory으로 시작하여 AST/ANTLR 광기로 내려갑니다. 이론적으로는 메타 데이터에 의존하지 않고 작동하는 파서를 해킹 할 수는 있지만이 작업을 수행하기 위해 노력하고있는 것이 무엇인지 상상하기가 가장 힘듭니다. 아마도 당신은 분명히 할 수 있을까요? 거기 더 나은 접근 방법이있다.

2

업데이트 : HQLQueryPlan을 직접 사용하는 일부 HQL의 오프라인 드라이 런을위한 좋은 접근 방법입니다. 실행 중일 때 앱의 모든 쿼리를 가로 채서 SQL을 기록하려면 아래 설명 된대로 프록시와 리플렉션을 사용해야합니다.

기준 쿼리에 대해서는 this answer을 참조하십시오.

HQL의 경우 Hibernate 구현 클래스로 캐스트하거나 private 멤버에 액세스해야하므로 지원되는 방법은 아니지만 3.2-2.3 버전의 Hibernate에서 작동합니다. 쿼리와 함께 갈 수

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]; 
} 

내가 시도/캐치에이 모든 것을 감싸는 것 : 다음은 HQL에서 쿼리를 액세스 할 수있는 코드가 (쿼리 session.createQuery (hql_string)에 의해 반환되는 객체입니다 로깅이 작동하지 않는 경우.

세션을 프록시 한 다음 쿼리를 프록시 처리하여 모든 쿼리 (hql, sql, criteria)의 매개 변수를 실행하기 전에 쿼리를 빌드해야하는 코드없이 실행할 수 있습니다. (초기 세션이 사용자가 제어하는 ​​코드에서 검색되는 한).

+0

이 모든 리플렉션을 망쳐 놓은 것은 완전히 필요하지 않습니다. 'HQLQueryPlan'은 public 생성자를 가지고 있습니다; 세션 팩토리를'SessionFactoryImplementor'로 캐스트하면됩니다. – ChssPly76

+0

사실, 그의 질문을 다시 읽은 후, 아마도 그가 필요한 모든 것입니다. 저는 쿼리를 실행하는 앱의 모든 클래스를 변경하지 않고도 애플리케이션에서 실시간으로 실행되는 모든 쿼리에 대해 HQL/SQL을 캡처하고자하는 상황을 해결했습니다. 삭제 권한이 없으므로 명확히 할 라인을 추가했습니다. –

+0

충분히 공정하게; 단지 당신이하고 싶은 것이 SQL을 포획하는 것이라면 간단한 appender를 작성하고 그것을 org.hibernate.SQL'에 첨부하는 것이 더 쉽습니다 (그리고 Hibernate 업데이트를 견디는 것이 훨씬 더 쉽습니다) :-) – ChssPly76