Trang chủHướng dẫnHibernate Native SQL Query: Cách viết, sử dụng và tối ưu hiệu suất
Java

Hibernate Native SQL Query: Cách viết, sử dụng và tối ưu hiệu suất

CyStack blog 6 phút để đọc
CyStack blog30/07/2025
Locker Avatar

Chris Pham

Technical Writer

Locker logo social
Reading Time: 6 minutes

Chúng ta đã tìm hiểu về Hibernate Query Language và Hibernate Criteria trong các bài viết trước. Hôm nay chúng ta sẽ khám phá Hibernate Native SQL query với các ví dụ minh họa.

Hibernate Native SQL Query

Hibernate SQL Query

Hibernate cung cấp tùy chọn thực thi các truy vấn SQL thuần (native SQL queries) thông qua việc sử dụng đối tượng SQLQuery. Hibernate SQL Query rất hữu ích khi chúng ta phải thực thi các truy vấn đặc thù của nhà cung cấp cơ sở dữ liệu mà Hibernate API không hỗ trợ. Ví dụ: các query hints hoặc từ khóa CONNECT trong Oracle Database.

Đối với các trường hợp thông thường, Hibernate SQL query không phải là cách tiếp cận được khuyến nghị vì chúng ta sẽ mất đi các lợi ích liên quan đến quản lý quan hệ giữa các entity (Hibernate association)bộ nhớ đệm cấp một (first level cache). Tôi sẽ sử dụng cơ sở dữ liệu MySQL và thiết lập bảng và dữ liệu tương tự như đã sử dụng trong ví dụ HQL, vì vậy bạn nên kiểm tra phần đó trước để hiểu các bảng và ánh xạ lớp mô hình tương ứng.

Ví dụ về Hibernate Native SQL Query

Đối với Hibernate Native SQL Query, chúng ta sử dụng Session.createSQLQuery(String query) để tạo đối tượng SQLQuery và thực thi nó. Ví dụ, nếu bạn muốn đọc tất cả các bản ghi từ bảng Employee, chúng ta có thể thực hiện thông qua đoạn mã dưới đây.

// Prep work
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.getCurrentSession();

// Get All Employees
Transaction tx = session.beginTransaction();
SQLQuery query = session.createSQLQuery("select emp_id, emp_name, emp_salary from Employee");
List<Object[]> rows = query.list();
for(Object[] row : rows){
	Employee emp = new Employee();
	emp.setId(Long.parseLong(row[0].toString()));
	emp.setName(row[1].toString());
	emp.setSalary(Double.parseDouble(row[2].toString()));
	System.out.println(emp);
}

Khi chúng ta thực thi đoạn mã trên với thiết lập dữ liệu hiện có, nó sẽ tạo ra kết quả như sau.

Hibernate: select emp_id, emp_name, emp_salary from Employee
Id= 1, Name= Pankaj, Salary= 100.0, {Address= null}
Id= 2, Name= David, Salary= 200.0, {Address= null}
Id= 3, Name= Lisa, Salary= 300.0, {Address= null}
Id= 4, Name= Jack, Salary= 400.0, {Address= null}

Lưu ý rằng phương thức list() trả về một List các mảng Object. Chúng ta cần phân tích cú pháp của chúng một cách rõ ràng thành double, long, v.v. Các lớp Employee và Address của chúng ta có các triển khai phương thức toString() như sau:

@Override
public String toString() {
	return "Id= " + id + ", Name= " + name + ", Salary= " + salary
			+ ", {Address= " + address + "}";
}
@Override
public String toString() {
	return "AddressLine1= " + addressLine1 + ", City=" + city
			+ ", Zipcode=" + zipcode;
}

Lưu ý rằng truy vấn của chúng ta không trả về dữ liệu Address, trong khi nếu chúng ta sử dụng truy vấn HQL "from Employee", nó cũng trả về dữ liệu bảng liên kết.

Hibernate SQL Query addScalar

Hibernate sử dụng ResultSetMetadata để suy ra kiểu dữ liệu của các cột được trả về bởi truy vấn. Từ góc độ hiệu suất, chúng ta có thể sử dụng phương thức addScalar() để xác định kiểu dữ liệu của cột. Tuy nhiên, chúng ta vẫn sẽ nhận được dữ liệu dưới dạng mảng Object.

//Get All Employees - addScalar example
query = session.createSQLQuery("select emp_id, emp_name, emp_salary from Employee")
		.addScalar("emp_id", new LongType())
		.addScalar("emp_name", new StringType())
		.addScalar("emp_salary", new DoubleType());
rows = query.list();
for(Object[] row : rows){
	Employee emp = new Employee();
	emp.setId(Long.parseLong(row[0].toString()));
	emp.setName(row[1].toString());
	emp.setSalary(Double.parseDouble(row[2].toString()));
	System.out.println(emp);
}

Đầu ra tạo ra sẽ giống nhau, tuy nhiên chúng ta sẽ thấy một chút cải thiện về hiệu suất khi lượng dữ liệu lớn.

Hibernate Native SQL nhiều bảng

Nếu chúng ta muốn lấy dữ liệu từ cả bảng EmployeeAddress, chúng ta có thể đơn giản viết truy vấn SQL cho việc đó và phân tích cú pháp tập kết quả.

query = session.createSQLQuery("select e.emp_id, emp_name, emp_salary,address_line1, city,
	zipcode from Employee e, Address a where a.emp_id=e.emp_id");
rows = query.list();
for(Object[] row : rows){
	Employee emp = new Employee();
	emp.setId(Long.parseLong(row[0].toString()));
	emp.setName(row[1].toString());
	emp.setSalary(Double.parseDouble(row[2].toString()));
	Address address = new Address();
	address.setAddressLine1(row[3].toString());
	address.setCity(row[4].toString());
	address.setZipcode(row[5].toString());
	emp.setAddress(address);
	System.out.println(emp);
}

Đối với đoạn mã trên, đầu ra được tạo ra sẽ trông như sau:

Hibernate: select e.emp_id, emp_name, emp_salary,address_line1, city, zipcode from Employee e, Address a where a.emp_id=e.emp_id
Id= 1, Name= Pankaj, Salary= 100.0, {Address= AddressLine1= Albany Dr, City=San Jose, Zipcode=95129}
Id= 2, Name= David, Salary= 200.0, {Address= AddressLine1= Arques Ave, City=Santa Clara, Zipcode=95051}
Id= 3, Name= Lisa, Salary= 300.0, {Address= AddressLine1= BTM 1st Stage, City=Bangalore, Zipcode=560100}
Id= 4, Name= Jack, Salary= 400.0, {Address= AddressLine1= City Centre, City=New Delhi, Zipcode=100100}

Hibernate Native SQL Entity và Join

Chúng ta cũng có thể sử dụng các phương thức addEntity()addJoin() để lấy dữ liệu từ bảng liên kết bằng cách sử dụng phép nối bảng (join). Ví dụ, dữ liệu trên cũng có thể được truy xuất như dưới đây.

//Join example with addEntity and addJoin
query = session.createSQLQuery("select {e.*}, {a.*} from Employee e join Address a ON e.emp_id=a.emp_id")
		.addEntity("e",Employee.class)
		.addJoin("a","e.address");
rows = query.list();
for (Object[] row : rows) {
    for(Object obj : row) {
    	System.out.print(obj + "::");
    }
    System.out.println("\\n");
}
//Above join returns both Employee and Address Objects in the array
for (Object[] row : rows) {
	Employee e = (Employee) row[0];
	System.out.println("Employee Info::"+e);
	Address a = (Address) row[1];
	System.out.println("Address Info::"+a);
}

{[aliasname].*} được dùng để trả về tất cả các thuộc tính của một entity. Khi chúng ta sử dụng addEntity() và addJoin() với các truy vấn nối như trên, nó sẽ trả về cả hai đối tượng, như đã minh họa. Đầu ra được tạo bởi đoạn mã trên sẽ trông như dưới đây.

Hibernate: select e.emp_id as emp_id1_1_0_, e.emp_name as emp_name2_1_0_, e.emp_salary as emp_sala3_1_0_, a.emp_id as emp_id1_0_1_, a.address_line1 as address_2_0_1_, a.city as city3_0_1_, a.zipcode as zipcode4_0_1_ from Employee e join Address a ON e.emp_id=a.emp_id
Id= 1, Name= Pankaj, Salary= 100.0, {Address= AddressLine1= Albany Dr, City=San Jose, Zipcode=95129}::AddressLine1= Albany Dr, City=San Jose, Zipcode=95129::

Id= 2, Name= David, Salary= 200.0, {Address= AddressLine1= Arques Ave, City=Santa Clara, Zipcode=95051}::AddressLine1= Arques Ave, City=Santa Clara, Zipcode=95051::

Id= 3, Name= Lisa, Salary= 300.0, {Address= AddressLine1= BTM 1st Stage, City=Bangalore, Zipcode=560100}::AddressLine1= BTM 1st Stage, City=Bangalore, Zipcode=560100::

Id= 4, Name= Jack, Salary= 400.0, {Address= AddressLine1= City Centre, City=New Delhi, Zipcode=100100}::AddressLine1= City Centre, City=New Delhi, Zipcode=100100::

Employee Info::Id= 1, Name= Pankaj, Salary= 100.0, {Address= AddressLine1= Albany Dr, City=San Jose, Zipcode=95129}
Address Info::AddressLine1= Albany Dr, City=San Jose, Zipcode=95129
Employee Info::Id= 2, Name= David, Salary= 200.0, {Address= AddressLine1= Arques Ave, City=Santa Clara, Zipcode=95051}
Address Info::AddressLine1= Arques Ave, City=Santa Clara, Zipcode=95051
Employee Info::Id= 3, Name= Lisa, Salary= 300.0, {Address= AddressLine1= BTM 1st Stage, City=Bangalore, Zipcode=560100}
Address Info::AddressLine1= BTM 1st Stage, City=Bangalore, Zipcode=560100
Employee Info::Id= 4, Name= Jack, Salary= 400.0, {Address= AddressLine1= City Centre, City=New Delhi, Zipcode=100100}
Address Info::AddressLine1= City Centre, City=New Delhi, Zipcode=100100

Bạn có thể chạy cả hai truy vấn trong MySQL client và nhận thấy rằng kết quả đầu ra tạo ra là giống nhau.

mysql> select e.emp_id as emp_id1_1_0_, e.emp_name as emp_name2_1_0_, e.emp_salary as emp_sala3_1_0_, a.emp_id as emp_id1_0_1_, a.address_line1 as address_2_0_1_, a.city as city3_0_1_, a.zipcode as zipcode4_0_1_ from Employee e join Address a ON e.emp_id=a.emp_id;
+--------------+----------------+----------------+--------------+----------------+-------------+---------------+
| emp_id1_1_0_ | emp_name2_1_0_ | emp_sala3_1_0_ | emp_id1_0_1_ | address_2_0_1_ | city3_0_1_  | zipcode4_0_1_ |
+--------------+----------------+----------------+--------------+----------------+-------------+---------------+
|            1 | Pankaj         |            100 |            1 | Albany Dr      | San Jose    | 95129         |
|            2 | David          |            200 |            2 | Arques Ave     | Santa Clara | 95051         |
|            3 | Lisa           |            300 |            3 | BTM 1st Stage  | Bangalore   | 560100        |
|            4 | Jack           |            400 |            4 | City Centre    | New Delhi   | 100100        |
+--------------+----------------+----------------+--------------+----------------+-------------+---------------+
4 rows in set (0.00 sec)

mysql> select e.emp_id, emp_name, emp_salary,address_line1, city, zipcode from Employee e, Address a where a.emp_id=e.emp_id;
+--------+----------+------------+---------------+-------------+---------+
| emp_id | emp_name | emp_salary | address_line1 | city        | zipcode |
+--------+----------+------------+---------------+-------------+---------+
|      1 | Pankaj   |        100 | Albany Dr     | San Jose    | 95129   |
|      2 | David    |        200 | Arques Ave    | Santa Clara | 95051   |
|      3 | Lisa     |        300 | BTM 1st Stage | Bangalore   | 560100  |
|      4 | Jack     |        400 | City Centre   | New Delhi   | 100100  |
+--------+----------+------------+---------------+-------------+---------+
4 rows in set (0.00 sec)

mysql>

Hibernate Native SQL Query với Tham số

Chúng ta có thể truyền tham số vào các truy vấn Hibernate SQL tương tự như JDBC PreparedStatement. Các tham số có thể được đặt bằng cách sử dụng tên hoặc chỉ số, như được minh họa trong ví dụ dưới đây.

query = session
		.createSQLQuery("select emp_id, emp_name, emp_salary from Employee where emp_id = ?");
List<Object[]> empData = query.setLong(0, 1L).list();
for (Object[] row : empData) {
	Employee emp = new Employee();
	emp.setId(Long.parseLong(row[0].toString()));
	emp.setName(row[1].toString());
	emp.setSalary(Double.parseDouble(row[2].toString()));
	System.out.println(emp);
}

query = session
		.createSQLQuery("select emp_id, emp_name, emp_salary from Employee where emp_id = :id");
empData = query.setLong("id", 2L).list();
for (Object[] row : empData) {
	Employee emp = new Employee();
	emp.setId(Long.parseLong(row[0].toString()));
	emp.setName(row[1].toString());
	emp.setSalary(Double.parseDouble(row[2].toString()));
	System.out.println(emp);
}

Đầu ra được tạo bởi đoạn mã trên sẽ là:

Hibernate: select emp_id, emp_name, emp_salary from Employee where emp_id = ?
Id= 1, Name= Pankaj, Salary= 100.0, {Address= null}
Hibernate: select emp_id, emp_name, emp_salary from Employee where emp_id = ?
Id= 2, Name= David, Salary= 200.0, {Address= null}

Đó là toàn bộ phần giới thiệu ngắn gọn về Hibernate SQL Query. Bạn nên tránh sử dụng nó trừ khi bạn muốn thực thi bất kỳ truy vấn cụ thể nào của cơ sở dữ liệu.

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất