文章目录
1. 对象图导航查询
对象图导航检索方式是根据已经加载的对象,导航到他的关联对象,它利用类与类之间的关系来检索对象。例如要查找一个联系人对应的客户,就可以由联系人对象自动导航找到联系人所属的客户对象。当然,前提是必须在对象关系映射文件上配置了多对一的关系,其检索方式如下所示:
LinkMan linkMan = (LinkMan)session.get(LinkMan.class, 1L);
Customer customer = linkMan.getCustomer();
2. OID查询
OID检索方式主要指用Session的get和load方法加载某条记录对应的对象。如下面两种加载客户对象的方式,就是OID检索方式,具体如下:
Customer customer1 = (Customer)session.get(Customer.class, 1L);
Customer customer2 = (Customer)session.load(Customer.class, 2L);
3. HQL查询
HQL(Hibernate Query Language)面向对象的查询语言,它和SQL查询语言有些相似,但它使用的是类、对象和属性的概念,而没有表和字段的概念。在Hibernate提供的各种检索方式中,HQL是官方推荐的查询语言,也是使用最广泛的一种检索方式,它具有如下功能:
- 在查询语句中设定各种查询条件。
- 支持投影查询,即仅检索出对象的部分属性。
- 支持分页查询。
- 支持分组查询,允许使用group by和having关键字。
- 提供内置聚集函数,如sum()、min()、max()。
- 能够调用用户定义的SQL函数。
- 支持子查询,即嵌套查询。
- 支持动态绑定参数。
Hibernate提供的Query接口是专门的HQL查询接口,它能够执行各种复杂的HQL查询语句。完整的HQL语句结构如下:
select...from...where...group by...having...order by...asc/desc
可见HQL查询非常类似于标准SQL查询。通常情况下,当检索数据表中的所有记录时,查询语句中可以省略select关键字,示例如下所示:
String hql = "from Customer";
如果执行该查询语句,则会返回应用程序中的所有Customer对象,需要注意的是Customer是类名,而不是表名,类名需要区分大小写,而关键字from不区分大小写。我们已经对HQL有了基本的了解,那么我们具体的来使用一下HQL。
3.1 基本查询
public void test1(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
String hql = " from cn.joker.domain.Customer "; //完整写法
String hql1 = " from Customer "; //简单写法
Query query = session.createQuery(hql1);
List<Customer> list = query.list();
System.out.println(list);
transaction.commit();
session.close();
sessionFactory.close();
}
3.2 条件查询
public void test2(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
//String hql1 = " from Customer where cust_id =? ";
String hql2 = " from Customer where cust_id = :id ";
Query query = session.createQuery(hql2);
//query.setParameter(0, 2L);
query.setParameter("id", 2L);
List<Customer> list = query.list();
System.out.println(list);
transaction.commit();
session.close();
sessionFactory.close();
}
3.3 分页查询
public void test3(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
String hql = " from Customer ";
Query query = session.createQuery(hql);
query.setFirstResult(2);
query.setMaxResults(10);
List<Customer> list = query.list();
System.out.println(list);
transaction.commit();
session.close();
sessionFactory.close();
}
3.4 排序查询
public void test4(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
String hql = " from Customer order by cust_id desc ";
Query query = session.createQuery(hql);
List<Customer> list = query.list();
System.out.println(list);
transaction.commit();
session.close();
sessionFactory.close();
}
3.5 统计查询
public void test5(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
String hql1 = " select count(*) from Customer ";
String hql2 = " select sum(cust_id) from Customer ";
String hql3 = " select avg(cust_id) from Customer ";
String hql4 = " select max(cust_id) from Customer ";
String hql5 = " select min(cust_id) from Customer ";
Query query = session.createQuery(hql5);
Number number = (Number) query.uniqueResult();
System.out.println(number);
transaction.commit();
session.close();
sessionFactory.close();
}
3.6 投影查询
public void test6(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
String hql1 = " select cust_name from Customer ";
String hql2 = " select cust_name, cust_id from Customer ";
String hql3 = " select new Customer(cust_id, cust_name) from Customer ";
Query query = session.createQuery(hql3);
List<Object> list = query.list();
System.out.println(list);
transaction.commit();
session.close();
sessionFactory.close();
}
4. QBC查询
QBC(Query By Criteria)是Hibernate提供的另一种检索对象的方式,它主要由Criteria接口、Criterion接口和Expression类组成,Criteria接口是Hibernate API中的一个查询接口,它需要由session进行创建。Criterion是Criteria的查询条件,在Criteria中提供了add(Criterion criterion)方法来添加查询条件。使用QBC检索对象的示例代码,如下所示:
//创建 criteria对象
Criteria criteria = session.createCriteria(Customer.class);
//设定查询条件
Criterion criterion = Restrictions.eq("id", 1);
//添加查询条件
criteria.add(criterion);
//执行查询,返回查询结果
List<Customer> cs = criteria.list();
上述代码中查询的是id为1的Customer对象。QBC检索是使用Restrictions对象编写查询条件的,在Restrictions类中提供了大量的静态方法来创建查询条件。其常用的方法如表所示。
4.1 基本查询
public void test1(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Criteria c = session.createCriteria(Customer.class);
List<Customer> list = c.list();
System.out.println(list);
transaction.commit();
session.close();
sessionFactory.close();
}
4.2 条件查询
public void test2(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Criteria c = session.createCriteria(Customer.class);
//c.add(Restrictions.idEq(2l));
c.add(Restrictions.eq("cust_id",2L));
List<Customer> list = c.list();
System.out.println(list);
transaction.commit();
session.close();
sessionFactory.close();
}
4.3 分页查询
public void test3(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Criteria c = session.createCriteria(Customer.class);
c.setFirstResult(0);
c.setMaxResults(2);
List<Customer> list = c.list();
System.out.println(list);
transaction.commit();
session.close();
sessionFactory.close();
}
4.4 排序查询
public void test4(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Criteria c = session.createCriteria(Customer.class);
c.addOrder(Order.asc("cust_id"));
//c.addOrder(Order.desc("cust_id"));
List<Customer> list = c.list();
System.out.println(list);
transaction.commit();
session.close();
sessionFactory.close();
}
4.5 统计查询
public void test5(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Criteria c = session.createCriteria(Customer.class);
//c.setProjection(Projections.count("custId"));
c.setProjection(Projections.rowCount());
Long long = c.uniqueResult();
System.out.println(long);
transaction.commit();
session.close();
sessionFactory.close();
}
5. 本地SQL查询
采用HQL或QBC检索方式时,Hibernate生成标准的SQL查询语句,适用于所有的数据库平台,因此这两种检索方式都是跨平台的。但有的应用程序可能需要根据底层数据库的SQL方言,来生成一些特殊的查询语句。在这种情况下,可以利用Hibernate提供的SQL检索方式。使用SQL检索方式检索对象的示例代码,如下所示:
public void test1(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
SQLQuery sqlQuery = session.createSQLQuery("select * from cst_linkman where lkm_gender = ?");
sqlQuery.setParameter(0, "男");
sqlQuery.addEntity(Linkman.class);
List<Linkman> list = sqlQuery.list();
System.out.println(list);
transaction.commit();
session.close();
sessionFactory.close();
}
在这,SQL的检索方式老王就不做太多的介绍。之前无论我们使用的是HQL或是QBC或是SQL其实都是单表的查询,而实际的开发中我们往往需要多个表的联合查询才可以获得我们想要的数据。那么接下来我们就来学习一下多表的查询吧。
6. 多表联合查询
Hibernate进行多表查询与SQL是很相似的,其实这些连接查询语法大致都是一致的,就是HQL查询的是对象而SQL查询的是表。那么我们来比较一下SQL和HQL的连接查询。
# SQL连接查询
SELECT * FROM cst_customer C INNER JOIN cst_linkman l ON c.cust_id = l.lkm_cust_id;
# HQL连接的查询
from Customer C inner join C.linkMans
在HQL中,我们可以不用写关联字段,因为客户中的联系人的集合其实对应的就是外键,所以我们在inner join的后面直接可以写C.linkMans。在控制台输出的语句的格式如下:
我们发现如果这样写HQL语句的话,生成的底层的SQL语句就是使用inner join进行连接,而连接的条件就是customer0_.cust_ id = linkmans1_.lkm_cust_id。所以HQL的连接可以不用写具体的on条件,直接写关联的属性即可。
那么我们已经知道了HQL的内连接的具体的写法了,那么迫切内连接和内连接写法和使用上有什么区别呢?迫切内连接其实就是在内连接的inner join后添加一个fetch关键字。我们通过下面的案例来比对一下:
// HQL内连接:将连接的两端对象分别返回,放到数组中
public void test1(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
String hql = " from Customer c inner join c.linkMans ";
Query query = session.createQuery(hql);
List<Object[]> list = query.list();
for(Object[] arr : list){
System.out.println(Arrays.toString(arr));
}
transaction.commit();
session.close();
sessionFactory.close();
}
// HQL迫切内连接:帮我们进行封装,返回值就是一个对象
public void test2(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
String hql = " from Customer c inner join fetch c.linkMans ";
Query query = session.createQuery(hql);
List<Customer> list = query.list();
System.out.println(list);
transaction.commit();
session.close();
sessionFactory.close();
}
我们会发现无论是内连接或是迫切内连接发送的底层SQL都是一样的,而且在生成的SQL语句中也没有fetch关键字,当然fetch本身就不是SQL语句的关键字。所以一定要注意,fetch只能在HQL中使用的,生成了SQL语句以后,fetch就消失了。
其实内连接和迫切内连接的主要区别就在于封装数据,因为他们查询的结果集都是一样的,生成底层的SQL语句也是一样的,区别如下:
- 内连接:发送就是内连接的语句,封装的时候将属于各自对象的数据封装到各自的对象中,最后得到一个List<Object[]>。
- 迫切内连接:发送的是内连接的语句,需要在编写HQL的时候在join后添加一个fetch关键字,Hibernate会发送HQL中的fetch关键字,从而将每条数据封装到对象中,最后得到一个List<Customer>。
但是迫切内连接封装以后会出现重复的数据,所以往往自己在手动编写迫切内连接的时候会使用distinct去掉重复值。