Tương tự như ngôn ngữ truy vấn SQL (Structured Query Language), Hibernate Query Language (HQL) được thiết kế nhằm mục đính tạo các truy vấn vào cơ sở dữ liệu. Tuy nhiên, thay vì thao tác với cột, hàng như SQL, ngôn ngữ HQL xem các bảng như 1 đối tượng (lớp/class) và các cột của chúng là những thuộc tính. Do đó, HQL được coi là ngôn ngữ truy vấn hướng đối tượng.
Ngoài ra HQL được hỗ trợ bởi Hibernate còn có những cấu hình giúp linh hoạt trong việc chuyển đổi mã HQL sang SQL do đó cũng giúp cho việc chuyển đổi hệ quản trị cơ sở dữ liệu dễ dàng hơn.
Các mệnh đề thông dụng
FROM
Khi giao tiếp với cơ sở dữ liệu, mỗi bảng (table) sẽ được HQL coi là 1 đối tượng và những thuộc tính là các cột. Thay vì tương tác trực tiếp lên cột và bảng dữ liệu sẽ lập trình để tương tác lên các thuộc tính và đối tượng dựa vào những gì được định nghĩa trong các Entity.
Thay vì cần lấy toàn các dòng dữ liệu, với lựa chọn là tất cả cột từ các bảng articles thì truy vấn với HQL cần tập trung vào việc lấy 1 danh sách mà trong đó toàn bộ thuộc tính của đối tượng Article được lấy.
Lấy toàn bộ dữ liệu từ bảng articles với truy vấn như sau.
String hql = "FROM Article"; Query query = session.createQuery(hql); List results = query.list();
Bên cạnh đó, có thể khai báo rõ ràng package class.
String hql = "FROM com.stdio.java.Article"; Query query = session.createQuery(hql); List results = query.list();
* Lưu ý đây là tên class Article
, được định nghĩa là 1 Entity chứ không phải là bảng articles trong cơ sở dữ liệu.
AS
Trong SQL, mệnh đề AS
được dùng để gán tên lớp với tên khai báo khác ngắn hơn, giúp tiết kiệm thời gian khi viết các câu truy vấn phức tạp, chức năng này của AS cũng tương tự trong HQL.
String hql = "FROM Article AS A"; Query query = session.createQuery(hql); List results = query.list();
Khi muốn gán tên class, không ghi mệnh đề AS
cũng được chấp nhận.
String hql = "FROM Article A"; Query query = session.createQuery(hql); List results = query.list();
SELECT
Mệnh đề thông dụng nhất trong việc truy vấn dữ liệu, SELECT
cho phép khai báo rõ ràng hơn việc sẽ chọn những thuộc tính, cột nào trong class Article
.
String hql = "SELECT A.id, A.title FROM Article A"; Query query = session.createQuery(hql); List results = query.list();
WHERE
Mệnh đề WHERE
được dùng để thêm các điều kiện, giúp xác định được đối tượng cần truy vấn trong cơ sở dữ liệu.
String hql = "FROM Article A WHERE A.id = 600"; Query query = session.createQuery(hql); List results = query.list();
ORDER BY
Sau khi câu truy vấn đã tìm được những đối tượng phù hợp với yêu cầu, có thể sắp xếp các đối tượng tăng dần hay giảm dần theo thuộc tính.
String hql = "FROM Article A WHERE A.date_created > 2015 ORDER BY A.views DESC"; Query query = session.createQuery(hql); List results = query.list();
Các thuộc tính để sắp xếp có thể được ghi như sau.
String hql = "FROM Article A WHERE A.date_created > 2015 ORDER BY A.views ASC, A.date_created ASC"; Query query = session.createQuery(hql); List results = query.list();
GROUP BY
GROUPBY
cho phép gộp các đối tượng dựa trên 1 thuộc tính nào đó, câu truy vấn có mệnh đề này thường sẽ sử dụng thêm các phương thức tính toán như SUM
, COUNT
, ...
String hql = "SELECT SUM(A.views), A.category FROM Article A GROUPBY A.category"; Query query = session.createQuery(hql); List results = query.list();
Câu truy vấn trên sẽ tính tổng số lượt view (lượt xem) của các bài viết theo từng thể loại, sau đó xuất ra kết quả gồm tổng views
của từng thể loại đã được gom nhóm đó.
Tham số trong câu truy vấn
1 trong những hỗ trợ từ Hibernate là có thể truyền tham số vào câu truy vấn, giúp thao tác nhận thông tin nhập vào từ người dùng để gắn vào câu truy vấn trở nên nhanh chóng và có thể tránh được tấn công SQL Injection.
Để khai báo tham số sẽ được truyền, thêm dấu :
trước tham số trong câu truy vấn.
String hql = "FROM Article A WHERE A.id = :id"; Query query = session.createQuery(hql);
query.setParameter("id", 220);
List results = query.list();
Mệnh đề thay đổi dữ liệu UPDATE/DELETE
So với phiên bản Hibernate 2, Hibernate 3+ sử dụng phương thức khác để thực hiện việc UPDATE
hay DELETE
trong cơ sở dữ liệu.
String hql = "UPDATE Articles set author = :author WHERE id = :id"; Query query = session.createQuery(hql);
query.setParameter("author", "STDIO"); query.setParameter("id", 600);
int result = query.executeQuery(); System.out.println("Rows affected: " + result);
Trong đó, executeQuery()
thực hiện câu lệnh UPDATE
thông tin đối tượng nên kết quả trả về sẽ là số dòng bị thay đổi trong đối tượng Article
.
Câu lệnh Delete cũng được thực hiện tương tự.
String hql = "DELETE FROM Articles WHERE id = :id"; Query query = session.createQuery(hql);
query.setParameter("id", 12);
int result = query.executeUpdate(); System.out.println("Rows affected: " + result);
Lưu ý, việc UPDATE
hay DELETE
đều được coi là làm thay đổi cơ sở dữ liệu, do đó ta đều dùng hàm executeUpdate
.
Mệnh đề INSERT
Hibernate không hỗ trợ INSERT
theo cách thông thường như SQL INSERT INTO <TABLE> values(...)
.
Chỉ có thể INSERT
từ 1 dữ liệu đã có sẵn trong cơ sở dữ liệu (trường hợp này có thể xem như là phép sao chép dữ liệu giữa các bảng hơn là thêm 1 dữ liệu mới), có thể hiểu tính năng INSERT này không tương đương với INSERT
của SQL.
String hql = "INSERT INTO Article(title, date_created, author) SELECT title, date_created, author FROM Author_Article"; Query query = session.createQuery(hql); int result = query.executeUpdate(); System.out.println("Rows affected: " + result);
Câu lệnh trên sẽ INSERT
các dòng dữ liệu vào bảng articles từ bảng author_articles.
Thêm 1 đối tượng vào lớp
Hibernate chỉ hỗ trợ INSERT
dữ liệu có sẵn, do đó để thêm mới 1 đối tượng, chỉ cần sử dụng session.save()
.
Thay vì sử dụng hàm createQuery()
như ví dụ trên, tạo 1 đối tượng Article article
sau đó sử dụng session.save(article)
để lưu đối tượng vào cơ sở dữ liệu. Hibernate khi đó sẽ tự động thêm đối tượng này vào bảng articles.
Article article = new Article("New article", "8/5/2017", "STDIO"); session.save(article);
Các hàm tính toán
Ngôn ngữ truy vấn Hibernate sử dụng các hàm tính toán tương tự như SQL để thao tác với các đối tượng.
AVG(property)
: tính trung bình các giá trị theo thuộc tínhCOUNT(property)
: đếm số lần xuất hiện của giá trịMAX(property)
: lấy giá trị lớn nhất theo thuộc tínhMIN(property)
: lấy giá trị nhỏ nhất theo thuộc tínhSUM(property)
: tính tổng các giá trị theo thuộc tính
Truy vấn hỗ trợ phân trang
Phân trang là công việc cần thiết khi có nhiều kết quả trả về khi truy vấn, nếu hiện tất cả kết quả ra sẽ khiến ứng dụng trở nên rối rắm và, khó xem dữ liệu và ảnh hưởng hiệu suất.
Truy vấn vừa đủ dữ liệu nhằm phân trang (10 kết quả mỗi lần lấy dữ liệu) có thể làm như sau.
String hql = "FROM Article"; Query query = session.createQuery(hql);
query.setFirstResult(11); query.setMaxResults(20);
List results = query.list();
setFirstResult
đặt vị trí kết quả đầu tiên muốn lấy trong số những kết quả đã truy vấn được.setMaxResults
cho Hibernate biết số lượng kết quả tính từ vị trí đầu tiên đó.
Như vậy, khi người dùng xem trang kết quả đầu tiên (truy vấn sẽ trả về tất cả 40 kết quả nếu không chia trang), họ sẽ xem được kết quả từ 1 → 10. Khi sang trang thứ 2, họ sẽ xem được kết quả từ 11 → 20, ...