Search…

Xây Dựng Câu Truy Vấn trong Hibernate với HQL

17/09/20207 min read
HQL (Hibernate Query Language) hỗ trợ thao tác với cơ sở dữ liệu theo hướng đối tượng và mềm dẽo trong việc thay đổi hệ quản trị cơ sở dữ liệu.

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ính
  • COUNT(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ính
  • MIN(property): lấy giá trị nhỏ nhất theo thuộc tính
  • SUM(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, ...

Bài chung series

IO Stream

IO Stream Co., Ltd

30 Trinh Dinh Thao, Hoa Thanh ward, Tan Phu district, Ho Chi Minh city, Vietnam
+84 28 22 00 11 12
developer@iostream.co

383/1 Quang Trung, ward 10, Go Vap district, Ho Chi Minh city
Business license number: 0311563559 issued by the Department of Planning and Investment of Ho Chi Minh City on February 23, 2012

©IO Stream, 2013 - 2024