La Kiến Vinh So với SQL, HQL (Hibernate Query Language) hỗ trợ thao tác với cơ sở dữ liệu một cách nhanh chóng và thường được sử dụng rộng rãi hơn trong các dự án phần mềm viết bằng ngôn ngữ Java.
Nội dung bài viết

Giới thiệ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 và thao tác với chúng. 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ư một đố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.

Việc sử dụng HQL không quá phức tạp, do những câu truy vấn được viết bằng HQL sẽ được biên dịch bởi Hibernate và chuyển thành các câu truy vấn SQL thông thường để giao tiếp với cơ sở dữ liệu. Dưới đây là những từ khóa, mệnh đề thường được sử dụng trong HQL.

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à một đối tượng và những thuộc tính là các cột. Chúng ta có thể lấy toàn bộ dữ liệu từ bảng Articles với truy vấn như sau.

String hql = "FROM Articles";
Query query = session.createQuery(hql);
List results = query.list();

Bên cạnh đó, chúng ta có thể khai báo rõ ràng package class.

String hql = "FROM com.stdio.java.Articles";
Query query = session.createQuery(hql);
List results = query.list();

Lưu ý, các mệnh đề Select, From,.. có thể viết hoa thường tùy ý, tuy nhiên tên lớp hay package phải viết đúng như khai báo.

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 Articles AS A";
Query query = session.createQuery(hql);
List results = query.list();

Khi muốn gán tên class, việc không ghi mệnh đề AS cũng được chấp nhận.

String hql = "FROM Articles 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 chúng ta 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 Articles.

String hql = "SELECT A.id, A.title FROM Articles 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 Articles 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, chúng ta 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 nào đó.

String hql = "FROM Articles 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 Articles 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

Group by cho phép chúng ta gộp các đối tượng dựa trên một 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 Articles 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

Một trong những hỗ trợ từ Hibernate là chúng ta có thể truyền tham số vào câu truy vấn, việc này 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, chúng ta thêm dấu ":" trước tham số trong câu truy vấn.

String hql = "FROM Articles 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() chỉ 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 lớp Articles.

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

Các bạn cần lưu ý, Hibernate không hỗ trợ Insert theo cách thông thường như các câu lệnh SQL (insert into TABLE values..). Chúng ta chỉ có thể Insert đối tượng từ một lớp khác đã có sẵn, việc Insert một đối tượng mới tôi sẽ hướng dẫn ở mục tiếp theo trong bài viết.

String hql = "INSERT INTO Articles(title, date_created, author) SELECT title, date_created, author FROM Author_Articles";
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 đối tượng articles từ lớp Author_Articles (có sẵn) vào lớp Articles.

Thêm một đối tượng vào lớp

Như đã lưu ý, Hibernate chỉ hỗ trợ chúng ta Insert đối tượng từ một lớp có sẵn, do đó để thêm mới một đối tượng, chúng ta sẽ sử dụng session.save().

Thay vì sử dụng hàm createQuery() như các ví dụ trên, chúng ta sẽ tạo một đối tượng Article (gồm title, date_created, author) 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 lớp Articles.

Article new_article = new Article("New article", "8/5/2017", "STDIO");
session.save(new_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ợ chia trang

Chia trang là công việc cần thiết khi chúng ta 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. Truy vấn vừa đủ dữ liệu nhằm chia trang (10 kết quả mỗi lần lấy dữ liệu), chúng ta làm như sau.

String hql = "FROM Articles";
Query query = session.createQuery(hql);
query.setFirstResult(11);
query.setMaxResults(20);
List results = query.list();

Trong đó, setFirstResult sẽ đặt vị trí kết quả đầu tiên muốn lấy trong số những kết quả đã truy vấn được và setMaxResults sẽ 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, ...

THẢO LUẬN
Nghệ thuật nếu không có kỹ thuật chỉ là giấc mơ, kỹ thuật không bao gồm nghệ thuật thì chỉ là giải toán. Steven K Robert
ĐÓNG