Hôm nay, chúng ta sẽ cùng tìm hiểu về Criteria trong Hibernate.
Hibernate Criteria
Hầu hết chúng ta sử dụng HQL để truy vấn cơ sở dữ liệu và lấy kết quả. Tuy nhiên, HQL không phải là cách được ưu tiên khi cần cập nhật hoặc xóa dữ liệu, vì khi đó chúng ta phải xử lý thêm các mối quan hệ (associations) giữa các bảng.
Hibernate Criteria API cung cấp một cách tiếp cận hướng đối tượng để truy vấn cơ sở dữ liệu và lấy kết quả. Chúng ta không thể sử dụng Criteria trong Hibernate để thực hiện update, delete hoặc bất kỳ lệnh DDL nào.
Criteria trong Hibernate chỉ được dùng để lấy dữ liệu từ cơ sở dữ liệu theo phong cách hướng đối tượng. Trong ví dụ Hibernate Criteria này, tôi sẽ sử dụng cùng một cấu hình như trong ví dụ HQL, và sẽ minh họa cách sử dụng Criteria trong Hibernate để truy vấn dữ liệu. Một số cách sử dụng phổ biến của Hibernate Criteria API gồm:
- Hibernate Criteria API cung cấp Projection, cho phép chúng ta sử dụng các hàm tổng hợp (aggregate functions) như sum(), min(), max()…
- Hibernate Criteria API có thể được sử dụng cùng với
ProjectionList
để chỉ truy vấn và lấy về các cột được chọn. - Criteria trong Hibernate có thể được dùng để thực hiện các truy vấn join bằng cách kết hợp nhiều bảng. Các phương thức hữu ích cho việc join trong Hibernate Criteria gồm: createAlias(), setFetchMode() và setProjection().
- Criteria trong Hibernate API có thể được dùng để truy vấn dữ liệu kèm điều kiện. Phương thức hữu ích trong trường hợp này là add(), nơi chúng ta có thể thêm các Restrictions.
- Hibernate Criteria API cung cấp phương thức addOrder() mà chúng ta có thể sử dụng để sắp xếp kết quả truy vấn.
Đoạn mã dưới đây minh họa các cách sử dụng khác nhau của Hibernate Criteria API, và hầu hết là các phiên bản thay thế cho ví dụ trong hướng dẫn HQL.
package com.journaldev.hibernate.main;
import java.util.Arrays;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernateCriteriaExamples {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
// Prep work
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
//Get All Employees
Criteria criteria = session.createCriteria(Employee.class);
List<Employee> empList = criteria.list();
for(Employee emp : empList){
System.out.println("ID="+emp.getId()+", Zipcode="+emp.getAddress().getZipcode());
}
// Get with ID, creating new Criteria to remove all the settings
criteria = session.createCriteria(Employee.class)
.add(Restrictions.eq("id", new Long(3)));
Employee emp = (Employee) criteria.uniqueResult();
System.out.println("Name=" + emp.getName() + ", City="
+ emp.getAddress().getCity());
//Pagination Example
empList = session.createCriteria(Employee.class)
.addOrder(Order.desc("id"))
.setFirstResult(0)
.setMaxResults(2)
.list();
for(Employee emp4 : empList){
System.out.println("Paginated Employees::"+emp4.getId()+","+emp4.getAddress().getCity());
}
//Like example
empList = session.createCriteria(Employee.class)
.add(Restrictions.like("name", "%i%"))
.list();
for(Employee emp4 : empList){
System.out.println("Employees having 'i' in name::"+emp4.getName()+","+emp4.getAddress().getCity());
}
//Projections example
long count = (Long) session.createCriteria(Employee.class)
.setProjection(Projections.rowCount())
.add(Restrictions.like("name", "%i%"))
.uniqueResult();
System.out.println("Number of employees with 'i' in name="+count);
//using Projections for sum, min, max aggregation functions
double sumSalary = (Double) session.createCriteria(Employee.class)
.setProjection(Projections.sum("salary"))
.uniqueResult();
System.out.println("Sum of Salaries="+sumSalary);
//Join example for selecting few columns
criteria = session.createCriteria(Employee.class, "employee");
criteria.setFetchMode("employee.address", FetchMode.JOIN);
criteria.createAlias("employee.address", "address"); // inner join by default
ProjectionList columns = Projections.projectionList()
.add(Projections.property("name"))
.add(Projections.property("address.city"));
criteria.setProjection(columns);
List<Object[]> list = criteria.list();
for(Object[] arr : list){
System.out.println(Arrays.toString(arr));
}
// Rollback transaction to avoid messing test data
tx.commit();
// closing hibernate resources
sessionFactory.close();
}
Khi chúng ta chạy chương trình ví dụ Hibernate Criteria ở trên, sẽ nhận được kết quả như sau:
May 26, 2014 6:53:32 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {4.0.4.Final}
May 26, 2014 6:53:32 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {4.3.5.Final}
May 26, 2014 6:53:32 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
May 26, 2014 6:53:32 PM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
May 26, 2014 6:53:32 PM org.hibernate.cfg.Configuration configure
INFO: HHH000043: Configuring from resource: hibernate.cfg.xml
May 26, 2014 6:53:32 PM org.hibernate.cfg.Configuration getConfigurationInputStream
INFO: HHH000040: Configuration resource: hibernate.cfg.xml
May 26, 2014 6:53:32 PM org.hibernate.internal.util.xml.DTDEntityResolver resolveEntity
WARN: HHH000223: Recognized obsolete hibernate namespace <https://hibernate.sourceforge.net/>. Use namespace <https://www.hibernate.org/dtd/> instead. Refer to Hibernate 3.6 Migration Guide!
May 26, 2014 6:53:32 PM org.hibernate.cfg.Configuration doConfigure
INFO: HHH000041: Configured SessionFactory: null
Hibernate Configuration loaded
Hibernate serviceRegistry created
May 26, 2014 6:53:32 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH000402: Using Hibernate built-in connection pool (not for production use!)
May 26, 2014 6:53:32 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH000401: using driver [com.mysql.jdbc.Driver] at URL [jdbc:mysql://localhost/TestDB]
May 26, 2014 6:53:32 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH000046: Connection properties: {user=pankaj, password=****}
May 26, 2014 6:53:32 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH000006: Autocommit mode: false
May 26, 2014 6:53:32 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000115: Hibernate connection pool size: 20 (min=1)
May 26, 2014 6:53:32 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect
May 26, 2014 6:53:32 PM org.hibernate.engine.jdbc.internal.LobCreatorBuilder useContextualLobCreation
INFO: HHH000423: Disabling contextual LOB creation as JDBC driver reported JDBC version [3] less than 4
May 26, 2014 6:53:32 PM org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService
INFO: HHH000399: Using default transaction strategy (direct JDBC transactions)
May 26, 2014 6:53:32 PM org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select this_.emp_id as emp_id1_1_1_, this_.emp_name as emp_name2_1_1_, this_.emp_salary as emp_sala3_1_1_, address2_.emp_id as emp_id1_0_0_, address2_.address_line1 as address_2_0_0_, address2_.city as city3_0_0_, address2_.zipcode as zipcode4_0_0_ from EMPLOYEE this_ left outer join ADDRESS address2_ on this_.emp_id=address2_.emp_id
ID=1, Zipcode=95129
ID=2, Zipcode=95051
ID=3, Zipcode=560100
ID=4, Zipcode=100100
Hibernate: select this_.emp_id as emp_id1_1_1_, this_.emp_name as emp_name2_1_1_, this_.emp_salary as emp_sala3_1_1_, address2_.emp_id as emp_id1_0_0_, address2_.address_line1 as address_2_0_0_, address2_.city as city3_0_0_, address2_.zipcode as zipcode4_0_0_ from EMPLOYEE this_ left outer join ADDRESS address2_ on this_.emp_id=address2_.emp_id where this_.emp_id=?
Name=Lisa, City=Bangalore
Hibernate: select this_.emp_id as emp_id1_1_1_, this_.emp_name as emp_name2_1_1_, this_.emp_salary as emp_sala3_1_1_, address2_.emp_id as emp_id1_0_0_, address2_.address_line1 as address_2_0_0_, address2_.city as city3_0_0_, address2_.zipcode as zipcode4_0_0_ from EMPLOYEE this_ left outer join ADDRESS address2_ on this_.emp_id=address2_.emp_id order by this_.emp_id desc limit ?
Paginated Employees::4,New Delhi
Paginated Employees::3,Bangalore
Hibernate: select this_.emp_id as emp_id1_1_1_, this_.emp_name as emp_name2_1_1_, this_.emp_salary as emp_sala3_1_1_, address2_.emp_id as emp_id1_0_0_, address2_.address_line1 as address_2_0_0_, address2_.city as city3_0_0_, address2_.zipcode as zipcode4_0_0_ from EMPLOYEE this_ left outer join ADDRESS address2_ on this_.emp_id=address2_.emp_id where this_.emp_name like ?
Employees having 'i' in name::David,Santa Clara
Employees having 'i' in name::Lisa,Bangalore
Hibernate: select count(*) as y0_ from EMPLOYEE this_ where this_.emp_name like ?
Number of employees with 'i' in name=2
Hibernate: select sum(this_.emp_salary) as y0_ from EMPLOYEE this_
Sum of Salaries=1000.0
Hibernate: select this_.emp_name as y0_, address1_.city as y1_ from EMPLOYEE this_ inner join ADDRESS address1_ on this_.emp_id=address1_.emp_id
[Pankaj, San Jose]
[David, Santa Clara]
[Lisa, Bangalore]
[Jack, New Delhi]
May 26, 2014 6:53:32 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
INFO: HHH000030: Cleaning up connection pool [jdbc:mysql://localhost/TestDB]
Vì tôi đang sử dụng dự án ví dụ HQL, nên bạn sẽ cần import dự án đó, sau đó thêm lớp này để chương trình hoạt động. Hãy chú ý đến các câu lệnh hibernate queries được thực thi trong phần output thông qua đó bạn có thể tinh chỉnh truy vấn của mình và lấy đúng kết quả mong muốn. Trên đây là phần tóm tắt nhanh về Criteria trong Hibernate.