文章目录
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();
}
4.6 离线查询
三层架构中,Hibernate的Seesion应该出现在Dao层,在Web层和Service层都不应该出现。但当使用QBC查询时,我们需要在WEB或者Service层调用Session,创建Criteria对象,这就造成了矛盾。解决矛盾的方法有二:1、将参数向下传递(不可取,参数多的时候不好处理)。2、使用Criteria离线查询。
在WEB层和Service层可以使用DetachedCriteria对象来设置查询条件。该对象的获取不需要Session对象,可后期与Criteria对象进行转换,被称为离线对象。获得该对象的方式:DetachedCriteria dc = DetachedCriteria.forClass(“要查询的实体类字节码”);
public void test6(){
//service/web层
DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
dc.add(Restrictions.idEq(6L));//拼装条件,全部与普通Criteria一样
//dao层
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Criteria c = dc.getExecutableCriteria(session);
List list = c.list();
System.out.println(list);
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. 多表查询
//原生SQL
// 交叉连接-笛卡尔积(避免)
// select * from A,B
// 内连接
// |-隐式内连接
// select * from A,B where b.aid = a.id
// |-显式内连接
// select * from A [inner] join B on b.aid = a.id
// 外连接
// |- 左外
// select * from A left [outer] join B on b.aid = a.id
// |- 右外
// select * from A right [outer] join B on b.aid = a.id
//---------------------------------------------------------------------
//HQL的多表查询
//内连接(迫切)
//外连接
// |-左外(迫切)
// |-右外(迫切)
//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.linkMens ";
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.linkMens ";
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就消失了。那么fetch到底有什么作用呢?
其实内连接和迫切内连接的主要区别就在与封装数据,因为他们查询的结果集都是一样的,生成底层的SQL语句也是一样的,区别如下:
- 内连接:发送就是内连接的语句,封装的时候将属于各自对象的数据封装到各自的对象中,最后得到一个List<Object[]>。
- 迫切内连接:发送的是内连接的语句,需要在编写HQL的时候在join后添加一一个fetch关键字,Hibernate会发送HQL中的fetch关键字,从而将每条数据封装到对象中,最后得到一个List<Customer>。
但是迫切内连接封装以后会出现重复的数据,因为我们查询到目前有三条记录,就会被封装到三个对象中,其实我们真正的客户对象只有两个所以往往自己在手动编写迫切内连接的时候会使用distinct去掉重复值。