2009-12-10 30 views
5

Tôi muốn "chạy khô" truy vấn Hibernate HQL. Đó là tôi muốn biết những gì các truy vấn SQL thực tế Hibernate sẽ thực hiện từ truy vấn HQL đã cho mà không thực sự thực hiện truy vấn HQL đối với cơ sở dữ liệu thực.Hibernate và chạy HQL truy vấn tĩnh tĩnh

Tôi có quyền truy cập vào ánh xạ ngủ đông cho các bảng, chuỗi truy vấn HQL, dialect cho cơ sở dữ liệu của tôi. Tôi cũng có quyền truy cập vào cơ sở dữ liệu nếu cần.

Bây giờ, làm thế nào tôi có thể tìm hiểu tất cả các truy vấn SQL Hibernate có thể tạo ra từ HQL của tôi mà không thực sự thực hiện truy vấn đối với bất kỳ cơ sở dữ liệu nào? Có công cụ nào cho việc này không?

Lưu ý rằng nhiều truy vấn SQL có thể được tạo từ một truy vấn HQL và tập hợp các truy vấn SQL được tạo có thể khác nhau dựa trên nội dung của cơ sở dữ liệu.

Tôi không hỏi cách đăng nhập truy vấn SQL trong khi truy vấn HQL đang thực thi.

Chỉnh sửa: Tôi không nhớ kết nối với cơ sở dữ liệu để tìm nạp một số siêu dữ liệu, tôi chỉ không muốn thực hiện truy vấn.

Chỉnh sửa: Tôi cũng biết giới hạn và chênh lệch được áp dụng cho truy vấn. Tôi cũng có các tham số thực tế sẽ được liên kết với truy vấn.

Trả lời

5

Câu trả lời ngắn gọn là "bạn không thể". Câu trả lời dài là dưới đây.

Có hai phương pháp bạn có thể thực hiện:

A) Nhìn vào HQLQueryPlan class, đặc biệt là getSqlStrings() method của nó. Nó sẽ không giúp bạn có được chính xác SQL vì việc xử lý trước được thực hiện trước khi truy vấn được thực thi (các tham số bị ràng buộc, giới hạn/offset được áp dụng, v.v.) nhưng nó có thể đủ gần với những gì bạn muốn. Điều cần lưu ý ở đây là bạn sẽ cần một ví dụ thực tế SessionFactory để xây dựng HQLQueryPlan, có nghĩa là bạn sẽ không thể làm như vậy mà không cần "kết nối với bất kỳ cơ sở dữ liệu nào". Bạn có thể, tuy nhiên, sử dụng cơ sở dữ liệu trong bộ nhớ (SqlLite và thích) và có Hibernate tự động tạo lược đồ cần thiết cho nó.

B) Bắt đầu với ASTQueryTranslatorFactory và hạ xuống trạng thái điên loạn AST/ANTLR. Về lý thuyết, bạn có thể hack cùng một trình phân tích cú pháp có thể hoạt động mà không dựa vào siêu dữ liệu nhưng tôi có một thời gian khó khăn nhất để tưởng tượng bạn đang cố gắng làm gì để có giá trị. Có lẽ bạn có thể làm rõ? Có là cách tiếp cận tốt hơn.

2

Cập nhật: cho một hoạt động ngoại tuyến, chạy một số HQL, sử dụng HQLQueryPlan trực tiếp là một cách tiếp cận tốt. Nếu bạn muốn chặn mọi truy vấn trong ứng dụng, trong khi nó đang chạy và ghi lại SQL, bạn sẽ phải sử dụng proxy và phản chiếu như được mô tả bên dưới.

Hãy xem this answer cho Truy vấn tiêu chí. Đối với HQL, đó là khái niệm tương tự - bạn phải chuyển sang các lớp triển khai Hibernate và/hoặc truy cập các thành viên riêng tư, vì vậy nó không phải là phương thức được hỗ trợ, nhưng nó sẽ hoạt động với phiên bản Hibernate 3.2-3.3. Đây là đoạn mã để truy cập truy vấn từ HQL (query là đối tượng được trả về bởi 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]; 
} 

tôi sẽ quấn tất cả điều đó trong một try/catch, do đó bạn có thể tiếp tục truy vấn nếu việc ghi nhật ký không hoạt động.

Có thể proxy phiên của bạn và sau đó proxy truy vấn của bạn để bạn có thể đăng nhập sql và tham số của mỗi truy vấn (hql, sql, tiêu chí) trước khi nó chạy, mà không có mã xây dựng truy vấn phải làm bất cứ điều gì (miễn là phiên ban đầu được truy xuất từ ​​mã bạn kiểm soát).

+0

Tất cả điều này gây rối với sự phản chiếu là hoàn toàn không cần thiết. 'HQLQueryPlan' có một hàm tạo công khai; bạn chỉ cần chuyển nhà máy phiên của bạn thành 'SessionFactoryImplementor'. – ChssPly76

+0

Đúng, và sau khi đọc lại câu hỏi của mình, đó có lẽ là tất cả những gì anh ta cần. Tôi đã giải quyết tình huống mà bạn muốn nắm bắt HQL/SQL cho mỗi truy vấn chạy trong ứng dụng của bạn thời gian thực - mà không cần phải thay đổi mọi lớp trong ứng dụng thực thi truy vấn. Vì tôi không có quyền xóa, tôi đã thêm một dòng để làm rõ. –

+0

Đủ công bằng; mặc dù nếu tất cả các bạn muốn làm là để nắm bắt SQL nó có thể dễ dàng hơn (và nhiều khả năng để tồn tại Hibernate cập nhật) để viết một appender đơn giản và đính kèm nó vào 'org.hibernate.SQL' :-) – ChssPly76

Các vấn đề liên quan