Hibernate框架(三)Hibernate查询
- get=>oid查询
- 对象属性导航查询
- HQL查询
- Criteria
- 原生SQL
HQL查询
Hibernate Query Language:hibernate查询语言,该查询语言是面向对象的查询语言.
HQL语句中绝对不可能出现与数据库相关的信息,都是与对象相关的信息,该语言是Hibernate独有的语言,只能在hibernate中使用.
- 书写HQL语句
- 创建查询对象
- 执行查询
语法
1、基础语法
//书写HQL语句
//String hql = "select c from Customer c ";
String hql = "from Customer ";//简单写法
//创建查询对象
Query query = session.createQuery(hql);
//执行查询
List<Customer> list = query.list();
System.out.println(list);
2、投影查询
//查询一个属性
//书写HQL语句
String hql = "select c.cust_name from Customer c ";
//创建查询对象
Query query = session.createQuery(hql);
//执行查询
List<String> list = query.list();
System.out.println(list);
//查询两个属性封装到数组
//书写HQL语句
String hql = "select c.cust_id,c.cust_name from Customer c ";
//创建查询对象
Query query = session.createQuery(hql);
//执行查询
List<Object[]> list = query.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
//查询多个属性封装到对象
//书写HQL语句
String hql = "select new Customer(cust_id,cust_name) from Customer ";
//创建查询对象
Query query = session.createQuery(hql);
//执行查询
List<Customer> list = query.list();
System.out.println(list);
3、条件查询
//问号占位符
//书写HQL语句
String hql = " from Customer where cust_name like ? ";
//创建查询对象
Query query = session.createQuery(hql);
query.setParameter(0, "张%");//从0开始
//执行查询
List<Customer> list = query.list();
System.out.println(list);
//命名占位符
//书写HQL语句
String hql = " from Customer where cust_name like :name ";
//创建查询对象
Query query = session.createQuery(hql);
query.setParameter("name", "张%");//从0开始
//执行查询
List<Customer> list = query.list();
System.out.println(list);
4、分页查询
//书写HQL语句
String hql = " from Customer ";
//创建查询对象
Query query = session.createQuery(hql);
//设置分页
query.setFirstResult(0);//起始页,limit第一个问号
query.setMaxResults(2);//页大小,limit第二个问号
//执行查询
List<Customer> list = query.list();
System.out.println(list);
5、排序查询
asc升序/desc降序
//书写HQL语句
String hql = " from Customer order by cust_id desc ";
//创建查询对象
Query query = session.createQuery(hql);
//执行查询
List<Customer> list = query.list();
System.out.println(list);
6、聚合查询
- count
- max
- min
- avg
sum
//书写HQL语句 String hql = " select count(c) from Customer c "; //创建查询对象 Query query = session.createQuery(hql); //执行查询 Long count = (Long) query.uniqueResult(); System.out.println(count);
多表查询
原生SQL
交叉连接(笛卡尔积,开发中避免出现)
内连接
隐式内连接
select * from a,b where a.id = b.aid;
显示内连接
select * from a inner join b on a.id = b.aid;
外连接
左外连接
select * from a left join b on a.id = b.aid;
右外连接
select * from a right join b on a.id = b.aid;
HQL
内连接
//书写HQL语句
String hql = "from Customer c inner join c.linkMen ";
//创建查询对象
Query query = session.createQuery(hql);
//执行查询
List<Object[]> list = query.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
迫切内连接
//书写HQL语句
String hql = "from Customer c inner join fetch c.linkMen ";
//创建查询对象
Query query = session.createQuery(hql);
//执行查询
List<Customer> list = query.list();
System.out.println(list);
左/右外连接
//书写HQL语句
String hql = "from Customer c left join c.linkMen ";
//创建查询对象
Query query = session.createQuery(hql);
//执行查询
List<Object[]> list = query.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
迫切左/右外连接
//书写HQL语句
String hql = "from Customer c inner join fetch c.linkMen ";
//创建查询对象
Query query = session.createQuery(hql);
//执行查询
List<Customer> list = query.list();
System.out.println(list);
迫切连接:将查询结果封装成对象.
HQL多表查询只适合比较简单的多表查询,业务比较复杂的,仍然要用原生SQL查询.
Criteria查询
hibernate框架中独有的查询方式.Criteria是无语句面向对象查询.Criteria一般用于单表查询.
语法
1、基本查询
//创建Criteria查询对象
Criteria criteria = session.createCriteria(Customer.class);
//执行查询
List<Customer> list = criteria.list();
System.out.println(list);
2、条件查询
//创建Criteria查询对象
Criteria criteria = session.createCriteria(Customer.class);
//设置查询参数,between函数,第一个参数是要查询的属性,第二个是查询条件,第三个是查询条件,and包含多个条件
criteria.add(Restrictions.and(Restrictions.between("cust_id", 3l, 5l),
Restrictions.like("cust_name", "张%")));
//执行查询
List<Customer> list = criteria.list();
System.out.println(list);
3、分页查询
//创建Criteria查询对象
Criteria criteria = session.createCriteria(Customer.class);
//设置查询参数
criteria.setFirstResult(0);//limit的第一个参数
criteria.setMaxResults(2);//limit的第二个参数
//执行查询
List<Customer> list = criteria.list();
System.out.println(list);
4、排序查询
//创建Criteria查询对象
Criteria criteria = session.createCriteria(Customer.class);
//设置查询参数
criteria.addOrder(Order.asc("cust_id")); //升序
//criteria.addOrder(Order.desc("cust_id"));//降序
//执行查询
List<Customer> list = criteria.list();
System.out.println(list);
5、聚合查询
- count
- max
- min
- avg
sum
//创建Criteria查询对象 Criteria criteria = session.createCriteria(Customer.class); //设置查询参数,setProjection添加聚合函数,统计数量 criteria.setProjection(Projections.count("cust_id")); //执行查询 long count = (long) criteria.uniqueResult(); System.out.println(count);
离线Criteria查询对象
获得离线查询对象
//web层
//获得离线查询对象
DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
//添加条件
dc.add(Restrictions.like("cust_name", "张%"));
执行离线查询对象
//dao层
//将离线Criteria对象与session关联
Criteria criteria = dc.getExecutableCriteria(session);
//执行查询
List<Customer> list = criteria.list();
System.out.println(list);
原生SQL
使用数组封装每行记录
//书写SQL语句
String sql = "select * from cst_customer";
//执行sql查询对象
SQLQuery query = session.createSQLQuery(sql);
//指定将结果封装到哪个对象中
query.addEntity(Customer.class);
//执行查询
List<Customer> list = query.list();
System.out.println(list);
指定将结果封装到哪个对象
//书写SQL语句
String sql = "select * from cst_customer where cust_name like ?";
//执行sql查询对象
SQLQuery query = session.createSQLQuery(sql);
//设置参数值
query.setParameter(0, "张%");
//指定将结果封装到哪个对象中
query.addEntity(Customer.class);
//执行查询
List<Customer> list = query.list();
System.out.println(list);
参数查询:SQL中可以使用问号|命名占位符
//书写SQL语句
String sql = "select * from cst_customer where cust_name like :name";
//执行sql查询对象
SQLQuery query = session.createSQLQuery(sql);
//设置参数值
query.setParameter("name", "张%");
//指定将结果封装到哪个对象中
query.addEntity(Customer.class);
//执行查询
List<Customer> list = query.list();
System.out.println(list);
分页查询:Limit语法
//书写SQL语句
String sql = "select * from cst_customer limit ?,?";
//执行sql查询对象
SQLQuery query = session.createSQLQuery(sql);
//设置参数值
query.setParameter(0, 0);//设置起始页
query.setParameter(1, 2);//设置页大小
//指定将结果封装到哪个对象中
query.addEntity(Customer.class);
//执行查询
List<Customer> list = query.list();
System.out.println(list);
hibernate查询策略
类级别查询策略
API
- get方法:调用时立即查询数据库,不会应用任何加载策略
- load方法:默认情况下,执行load方法时,不会立即查询数据库,使用时才会执行查询.load方法会应用类级别加载策略
配置
<!-- lazy属性:懒加载|延迟加载
true(默认):懒加载|延迟加载
false:立即加载
-->
<class name="Customer" table="cst_customer" lazy="false" >
实现原理
在懒加载时,load不会立即查询,但是仍会返回一个对象,返回的对象要查询的对象的代理对象,这个代理对象会封装当前操作的session,在获得对象的属性时,能够根据关联的session加载数据
注意事项
返回的代理对象,初始化操作一定要确保在session关闭之前完成,不然会抛no-session异常.
关联级别查询策略
集合加载策略
一对多|多对多
lazy属性:决定集合加载策略
true(默认值):懒加载|延迟加载
false:立即加载
extra:极其懒惰,在查询集合数量时,只查询数量
fetch属性:指定集合的加载方式
select(默认值):在加载集合时使用单表查询加载
join:在加载集合时会使用左外连接查询
注:fetch=join时,lazy属性失效.
subselect:子查询,加载多个客户的集合时,子查询才有效,如果只是加载一个客户的集合,subselect与select一样
<set name="linkMen" inverse="true" lazy="true" fetch="subselect" >
<key column="lkm_cust_id" ></key>
<one-to-many class="LinkMan" />
</set>
属性加载策略
多对一
lazy属性:是否懒加载
proxy(默认值):由对方的类级别策略代我决定
false:立即加载
fetch属性:决定加载方式
select(默认值):单表查询加载关联数据
join:使用多表查询同时加载关联数据.
注意:使用join时,lazy属性失效
<many-to-one name="customer" column="lkm_cust_id" class="Customer" lazy="false" fetch="join" ></many-to-one>
查询策略总结
结论:查询策略中涉及的所有属性都使用默认值.
问题1. sql语句打印n+1问题
解决方案:batch-size属性:选择一次加载几个客户的集合,默认值:1
<set name="linkMen" inverse="true" batch-size="2">
问题2.no-session问题
dao返回的代理对象.Service中关闭了session.在web层使用了代理对象时,session已经关闭
解决方案:
1. 不使用getCurrentSession.自己将session与线程绑定
2. 使用过滤器,在过滤器的后处理器代码中关闭session.