post-image

Hướng dẫn các kiểu truy vấn HQL sql qua ví dụ

1. Tổng quan

Hibernate ORM framework cung cấp ngôn ngữ truy vấn gọi là Hibernate Query Language viết tắt là HQL. Nó rất mạnh mẽ và linh hoạt và có các đặc điểm sau:

  • Tương tự như SQL: Cú pháp của HQL rất giống với SQL chuẩn. Nếu bạn quen thuộc với SQL thì viết HQL sẽ khá dễ dàng: từ SELECT, FROM, ORDER BY đến các biểu thức số học và các hàm tổng hợp, vv
  • Hoàn toàn hướng đối tượng: HQL không sử dụng tên thật của bảng và cột trong cơ sở dữ liệu. Nó sử dụng tên lớp và tên thuộc tính thay thế. HQL có thể hiểu được thừa kế, đa hình và liên kết.
  • Không phân biệt chữ hoa chữ thường cho các từ khóa (keywords): Điều đó có nghĩa là SELECT, select, Select là như nhau.
  • Phân biệt chữ hoa chữ thường cho các lớp và thuộc tính của Java: HQL xem xét các trường hợp nhạy cảm cho các lớp Java và các thuộc tính của chúng, nghĩa là Person và person là hai đối tượng khác nhau.

Trong bài này, mình sẽ Hướng dẫn Hibernate Query Language (HQL) qua 14 ví dụ để thực hiện các truy vấn cơ bản (CRUD) cũng như các ứng dụng phổ biến khác. Lược đồ sau minh hoạ mối quan hệ của các bảng được sử dụng trong các ví dụ của hướng dẫn này:

Hướng dẫn Hibernate Query Language

Và đây là các lớp model đã map với JPA annotations:

Category class:

package net.codejava.hibernate;
 
import java.util.Set;
 
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
 
 
@Entity
@Table(name = "CATEGORY")
public class Category {
 
    private long id;
    private String name;
 
    private Set<Product> products;
 
    public Category() {
    }
 
    public Category(String name) {
        this.name = name;
    }
 
    @Id
    @Column(name = "CATEGORY_ID")
    @GeneratedValue
    public long getId() {
        return id;
    }
 
 
    @OneToMany(mappedBy = "category", cascade = CascadeType.ALL)
    public Set<Product> getProducts() {
        return products;
    }
 
    // other getters and setters
}

Product class:

package net.codejava.hibernate;
 
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
 
@Entity
@Table(name = "PRODUCT")
public class Product {
    private long id;
    private String name;
    private String description;
    private float price;
 
    private Category category;
 
    public Product() {
    }
 
    public Product(String name, String description, float price,
            Category category) {
        this.name = name;
        this.description = description;
        this.price = price;
        this.category = category;
    }
 
    @Id
    @Column(name = "PRODUCT_ID")
    @GeneratedValue
    public long getId() {
        return id;
    }
 
    @ManyToOne
    @JoinColumn(name = "CATEGORY_ID")
    public Category getCategory() {
        return category;
    }
 
    // other getters and setters
}

Order class:

package net.codejava.hibernate;
 
import java.util.Date;
 
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
 
@Entity
@Table(name = "ORDERS")
public class Order {
    private int id;
    private String customerName;
    private Date purchaseDate;
    private float amount;
    private Product product;
 
    @Id
    @Column(name = "ORDER_ID")
    @GeneratedValue
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    @Column(name = "CUSTOMER_NAME")
    public String getCustomerName() {
        return customerName;
    }
 
    @Column(name = "PURCHASE_DATE")
    @Temporal(TemporalType.DATE)
    public Date getPurchaseDate() {
        return purchaseDate;
    }
 
 
    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    public Product getProduct() {
        return product;
    }
 
    // other getters and setters
}

Hibernate Query Language (HQL) Example

Các ví dụ sắp tới được cung cấp dựa trên giả định rằng SessionFactory Hibernate được mở ra và một giao dịch(Transaction) đã được bắt đầu. Bạn có thể tìm hiểu thêm về cách lấy SessionFactory và bắt đầu một giao dịch trong hướng dẫn: Xây dựng Hibernate SessionFactory từ Service Registry. (updating)

1. Cách thực thi(execute) HQL trong Hibernate

Thực thi câu lệnh hql qua các bước dưới đây:

  • Viết câu lệnh HQL:
    String hql = "Your Query Goes Here";
  • Tạo câu truy vấn Query từ phiên làm việc Session:
    Query query = session.createQuery(hql);
  • Thực thi query có 2 dạng: là bạn muốn thực thi dạng xem danh sách listing hay thực thi dạng cập nhật:
    • Listing query (SELECT):
      List listResult = query.list();
    • Update query (INSERT, UPDATE, DELETE):
      int rowsAffected = query.executeUpdate();
  • Kết quả trả về từ câu truy vấn: phụ thuộc vào dạng truy vấn mà Hibernate trả về các kiểu kết quả khác nhau. Ví dụ:
    • Select query một đối tượng sẽ trả về một danh sách các đối tượng đó.
    • Join query trả về danh sách mảng Objects mà các bảng được kết với nhau(xem mỗi bảng là 1 object). Điều này cũng áp dụng cho các truy vấn sử dụng các hàm tổng hợp (count, sum, avg, etc).

Bây giờ chúng ta cùng vào các ví dụ chi tiết của Hướng dẫn Hibernate Query Language (HQL) qua ví dụ !

2. Ví dụ List Query

Đoạn mã sau đây thực thi một truy vấn mà kết quả trả về là danh sách Category:

String hql = "from Category";
Query query = session.createQuery(hql);
List<Category> listCategories = query.list();
 
for (Category aCategory : listCategories) {
    System.out.println(aCategory.getName());
}

Lưu ý rằng trong Hibernate Query Language(HQL), chúng ta có thể bỏ qua từ khoá SELECT và chỉ sử dụng FROM thay thế.

3. Ví dụ Search Query

Các câu lệnh thực hiện truy vấn tìm kiếm tất cả các sản phẩm trong một danh mục có tên là ‘Computer’:

String hql = "from Product where category.name = 'Computer'";
Query query = session.createQuery(hql);
List<Product> listProducts = query.list();
 
for (Product aProduct : listProducts) {
    System.out.println(aProduct.getName());
}

Điều thú vị ở đây là Hibernate tự động tạo truy vấn JOIN giữa bảng Product và Category một cách lặng im. Như lúc đầu mình đã nói HQL hoàn toàn hướng đối tượng và nó thể hiện rõ ở đây.  Vì vậy, chúng ta không phải sử dụng từ khóa JOIN ở câu này:

String hql = "from Product where category.name = 'Computer'";

4. Dùng tham số cho câu truy vấn (Named Parameters)

Bạn có thể dùng tham số cho câu truy vấn bằng cách sử dụng dấu hai chấm trước tên tham số, ví dụ :id cho biết một trình giữ chỗ cho một tham số có tên id. Ví dụ sau minh họa cách viết và thực hiện một truy vấn bằng cách sử dụng các tham số được đặt tên:

String hql = "from Product where description like :keyword";
 
String keyword = "New";
Query query = session.createQuery(hql);
query.setParameter("keyword", "%" + keyword + "%");
 
List<Product> listProducts = query.list();
 
for (Product aProduct : listProducts) {
    System.out.println(aProduct.getName());
}

Các câu lệnh Hibernate Query Language(HQL) ở trên cho kết quả là  tất cả các sản phẩm có mô tả chứa từ khoá được chỉ định(dòng 1). Sau đó sử dụng phương thức setParameter (name, value) để thiết lập giá trị thực cho tham số được đặt tên.(dòng 5)

Lưu ý rằng chúng ta muốn thực hiện một tìm kiếm LIKE để các dấu phần trăm phải được sử dụng bên ngoài chuỗi truy vấn, không giống như SQL truyền thống.

5. Ví dụ Insert – Select Query

HQL không hỗ trợ câu lệnh INSERT thông thường (bạn biết tại sao – vì phương thức session.save (Object) thực hiện nó rất tốt rồi). Vì vậy, chúng ta chỉ có thể viết INSERT … SELECT truy vấn trong HQL. Đoạn mã sau thực hiện truy vấn chèn tất cả các dòng dữ liệu từ bảng Category vào bảng OldCategory:

String hql = "insert into Category (id, name)"
        + " select id, name from OldCategory";
 
Query query = session.createQuery(hql);
 
int rowsAffected = query.executeUpdate();
if (rowsAffected > 0) {
    System.out.println(rowsAffected + "(s) were inserted");
}

Lưu ý rằng HQL là hướng đối tượng, vì vậy Category và OldCategory phải được ánh xạ các tên lớp (không phải tên bảng thật).

6. Ví dụ Update Query

Truy vấn UPDATE tương tự như SQL. Ví dụ sau chạy truy vấn cập nhật giá cho một sản phẩm cụ thể:

String hql = "update Product set price = :price where id = :id";
 
Query query = session.createQuery(hql);
query.setParameter("price", 488.0f);
query.setParameter("id", 43l);
 
int rowsAffected = query.executeUpdate();
if (rowsAffected > 0) {
    System.out.println("Updated " + rowsAffected + " rows.");
}

7. Ví dụ Delete Query

Sử dụng truy vấn DELETE trong HQL cũng dễ hiểu. Ví dụ:

String hql = "delete from OldCategory where id = :catId";
 
Query query = session.createQuery(hql);
query.setParameter("catId", new Long(1));
 
int rowsAffected = query.executeUpdate();
if (rowsAffected > 0) {
    System.out.println("Deleted " + rowsAffected + " rows.");
}

8. Ví dụ Join Query

HQL hỗ trợ các loại kết bảng Join (như SQL):

  • inner join (can be abbreviated as join).
  • left outer join (can be abbreviated as left join).
  • right outer join (can be abbreviated as right join).
  • full join

Ví dụ, đoạn lệnh dưới đây sẽ truy vấn mà kết quả trả về là Join giữa 2 bảng Product và Category:

String hql = "from Product p inner join p.category";

Query query = session.createQuery(hql);
List<Object[]> listResult = query.list();

for (Object[] aRow : listResult) {

    Product product = (Product) aRow[0];
    Category category = (Category) aRow[1];

    System.out.println(product.getName() + " - " + category.getName());
}

Dùng Join trên HQL là không tường minh. Chú ý rằng câu lệnh Join sẽ trả về 1 danh sách mảng Object, vì thế chúng ta cần xử lý kết quả trả về này:

List<Object[]> listResult = query.list();

HQL cung cấp từ khóa mà bạn có thể sử dụng trong trường hợp bạn muốn Join có điều kiện. Ví dụ:

from Product p inner join p.category with p.price > 500

Câu lệnh phía trên Join giữa Product và Category với nhau qua điều kiện là price của Produce > 500

Nếu bạn khó hiểu câu lệnh phía trên, chúng ta có thể viết từng minh như thế này cũng được:

from Product where category.name = 'Computer'

9. Ví dụ Sort Query

Sắp xếp trong HQL tương tự như SQL dùng lệnh ORDER BY theo đó là cột nào cần sắp xếp và sắp xếp theo hướng ASC(tăng dần) hay DESC(giảm dần). Ví dụ:

String hql = "from Product order by price ASC";

Query query = session.createQuery(hql);
List<Product> listProducts = query.list();

for (Product aProduct : listProducts) {

    System.out.println(aProduct.getName() + "\t - " + aProduct.getPrice());

}

Kết quả là lấy danh sách tất cả các sản phẩm sắp xếp tăng dần theo giá.

10. Ví dụ Group By Query

Dùng GROUP BY trong HQL tương tự SQL. Câu truy vấn dưới đây gom nhóm giá của tất cả sản phẩm cho mỗi thể loại:

select sum(p.price), p.category.name from Product p group by category

Đây là toàn bộ code:

String hql = "select sum(p.price), p.category.name from Product p group by category";

Query query = session.createQuery(hql);
List<Object[]> listResult = query.list();

for (Object[] aRow : listResult) {

    Double sum = (Double) aRow[0];
    String category = (String) aRow[1];
    System.out.println(category + " - " + sum);

}

Leave a Reply

Your email address will not be published. Required fields are marked *