回顾
写出下面两个类的Hibernate配置文件,注意关联的配置
预习检查
· Hibernate支持哪两种查询?
· HQL是什么?
本章任务
· 使用Hibernate实现,房屋查询DAO
· 对title模糊查询
· 对街道精确查询
· 对租金使用一个范围查询
· 查询特定联系人都在哪些街道发布了信息
· 提供分页查询方法
本章目标
· 掌握HQL查询
· 掌握Criteria查询
为什么使用HQL
· 如何使用Hibernate查询所有房屋信息?
如何使用HQL
常见错误
属性查询
· select fw from TblFwxxfw将查询整个对象信息,我们只想查询date和title怎么做?
select fw.title, fw.date fromTblFwxx fw
参数查询
参数查询:命名参数
小结
关联查询
小结
· 写出HQL语句:
查询“亚运村”街道的房屋信息中,涉及的房屋类型。
提示:亚运村街道的房屋信息: fw.jd.jdid=39
分页查询
· 实现分页查询方法:public List search(int pageNo, int pageSize) 。
统计函数
小结
对象查询
· 使用一个查询方法,同时支持三项功能:
· 对title模糊查询
· 对房屋类型精确查询
· 对租金使用一个范围查询
public List search(TblFwxx condition){
Stringhql = "select fw from TblFwxx fw "
hql+= "where 1=1 ";
if(condition.getTitle()!=null){
hql+= "and fw.title like '%" +
condition.getTitle()+ "%' ";
}
...
}
使用Criteria查询
总结
· HQL的全称是?
· 和SQL相比,HQL有哪些特点?
· HQL语句为:select jd.jdid,jd.jd from TblJd jd。怎样获得并显示查询结果?
· 使用'?'做占位符的参数查询,怎样设置参数的值?
· 命名参数查询的语法是?
· 怎样创建Criteria查询对象?
Hibernate对象条件查询:
查询通过如下三个类获取:
l Criteria 代表一次查询
l Criterion 代表一个查询条件
l Restrictions 产生查询条件的工具类
执行条件查询的步骤:
(1) 获得Hibernate的Session对象
(2) 以Session对象创建Criteria对象
(3) 使用Restrictions的静态方法创建Criterion查询条件
(4) 向Criteria查询中添加Criterion查询条件
(5) 执行Criteria的list等方法返回结果集
投影、聚合和分组
投影运算实际上是一种基于列的运算,通常用于投影到指定列(也就是过滤其他列,类似select子句的作用),还可以完成SQL语句中常用的分组、组筛选等功能。
Hibernate的条件过滤中使用Projection代表投影运算,Projection是一个接口,而Projections作为Projection的工厂,负责生成Projection对象。
Projections类提供了几个静态方法:
¨ avg(String propertyName) : 计算特定属性的平均值,类似于avg函数
¨ count(StringpropertyName) : 统计查询结果在某列上的记录条数。类似于count(column)函数
¨ countDistinct(StringpropertyName) : 统计查询结果在某列上不重复的记录条数。类似于count(distinctcolumn)函数。
¨ groupProperty(StringpropertyName) : 将查询结果按某列上的值进行分组。类似于添加groupby 子句。
¨ max(String propertyName) : 统计查询结果在某列上的最大值。类似于max函数。
¨ min(String propertyName) : 统计查询结果在某列上的最小值。类似于min函数。
¨ rowCount(): 统计查询结果的记录条数。类似于count(*)的功能。
¨ sum(String propertyName) : 统计查询结果在某列上的总和。类似于sum函数。
/** *分组查询方法 * */ publicvoid searchFwxxGroup(){ List list = new ArrayList(); Session session = HibernateSessionFactory.getSession(); //创建查询对象 Criteria c = session.createCriteria(Fwxx.class); c.setProjection( Projections.projectionList() //添加投影条件 //统计记录行数 .add(Projections.rowCount()) //按jdid分组 .add(Projections.groupProperty("tblJd")) ); list = c.list(); for (Object object : list) { Object[] objs =(Object[])object; //集合中每一个元素为object数据 System.out.println("行数:"+objs[0]); //前面的元素都是聚合函数的结果值 Jd jd = (Jd)objs[1]; //最后一个元素才是返回的查询对象 System.out.println("街道分组:"+jd.getJd()); } session.close(); } |
/** *查询对象某个属性集合 * */ publicvoid searchFwxxProperty(){ List list = new ArrayList(); Session session = HibernateSessionFactory.getSession(); //创建查询对象 Criteria c = session.createCriteria(Fwxx.class); c.setProjection( Property.forName("title") //过滤只筛选出title属性,不再返回整个Fwxx对象 ); list = c.list(); for (Object object : list) { System.out.println(object); } session.close(); } |
SQL查询
Hibernate支持使用原生SQL查询。SQL查询是通过SQL Query接口来表示的。SQLQuery是Query接口的子接口,因此完全可以调用Query接口的方法,但SQLQuery比Query多了如下两个重载方法
addEntity() : 将查询到的记录与特定实体关联
addScalar() : 将查询的记录关联成标量值
执行SQL查询的步骤:
(1) 获取Hibernate Session对象
(2) 编写SQL语句
(3) 以SQL语句作为参数,调用Session的createSQLQuery方法创建查询对象
(4) 调用SQLQuery对象的addScalar()或addEntity()方法将选出的结果与标量值或实体进行关联,分别用于进行标量查询或实体查询。
(5) 如果SQL语句包含参数,则调用Query的setXXX方法为参数赋值
(6) 调用Query的list方法返回查询结果集
标量查询
最基本的SQL查询就是获得一个标量(数值)的列表。如
List list =HibernateSessionFactory.getSession()
.createSQLQuery("select* from tbl_fwxx").list();
默认情况下,查询语句将返回的Object数组组成的list,数组每个元素都是fwxx表的列值。Hibernate会通过ResultSetMetadata来判定返回数据列的实际顺序和类型。
PS:如果select后面只有一个字段,那么返回的list集合元素就不是数组,而只是单个的变量值。
publicvoid sqlSearch(){ List list = HibernateSessionFactory.getSession() //创建sql查询,查询fwxx表中所有记录 .createSQLQuery("select * from tbl_fwxx") //只过滤出title列和fwid列,并指定类型 .addScalar("title",TypeFactory.basic("String")) .addScalar("fwid",TypeFactory.basic("Integer")) .list(); for (Object object : list) { Object[] objs = (Object[])object; //返回的数组中,第一个元素为title,第二个元素为fwid System.out.println(objs[0]+"\t"+objs[1]); } } |
实体查询
如果查询返回了某个数据表的全部数据列,且该数据表有对应的持久化类映射,我们就可把查询结果转换成实体查询。
publicvoid sqlSearchWithEntity(){ List list = HibernateSessionFactory.getSession() //创建sql查询,查询fwxx表中所有列 .createSQLQuery("select * from tbl_fwxx where uid = :uid") .addEntity(Fwxx.class) //指定所关联的实体 .setInteger("uid", 56) //设置参数 .list(); for (Object object : list) { Fwxx fw = (Fwxx)object; System.out.println(fw.getFwid()+"\t"+fw.getTitle()); } } |
调用存储过程
从Hibernate3开始,Hibernate可以通过命名SQL查询来调用存储过程。
1、在hbm.xml的映射文件中添加一个命名查询配置
<sql-query name="callQx" callable="true"> <return class="entity.Qx" alias="Q"> <return-property name="qxid" column="qxid"></return-property> <return-property name="qx" column="qx"></return-property> </return> { call proc_selectQx()} </sql-query> |
2、编写代码读取命名查询
Session session = HibernateSessionFactory.getSession(); Transaction tx = session.beginTransaction(); List list = session .getNamedQuery("callQx").list(); tx.commit(); session.close(); for (Object object : list) { Qx qx = (Qx)object; System.out.println(qx.getQxid()+"\t"+qx.getQx()); } |
总结
1.使用HQL的四步
Session session =HibernateDao.newInstance().getSession(); 获取session 相当于获取connection
String hql = "from FWXX"; String hql = "select fw from FWXXfw"; 编写hql语句相当于SQL语句,前面简单,后面是通过别名的形式
Query query =session.createQuery(hql); 创建Query对象,相当于statement对象
List<FWXX> list = query.list(); 执行查询,list集合接收数据,相当于ResultSet,不过把数据封装成了List集合
2.如果只查询表中的几个列的数据
3.迭代器,只查询几列的值,先封装成数组,多少列对应多少个元素,如果只有一个列,则只用一个Object对象接收
Iterator<FWXX> it = list.iterator();
while(it.hasNext())
{
FWXX fw = it.next();
System.out.println(fw.getTitle());
}
Iterator it = list.iterator();
while(it.hasNext())
{
Object[]arr = (Object[])it.next();
System.out.println(arr[0]+ "/t" + arr[1]);
}
4.hql查询设置
String hql = "select fw.jdid,fw.uidfrom FWXX fw where fw.jdid like ?";setString(0,?);
支持:>、< 、 = 、 >= 、 <= 、<> 和is null;and、or、not和括号;in和between
1. 必须保证:query设置参数的数目 == hql语句中占位符的数目
2. 占位符下标从 0 开始。
String hql = "select fw.jdid,fw.uidfrom FWXX fw where fw.jdid like :Z1";
query.setString("Z1","%2%");
String hql = "select fw from TblFwxxfw "hql += "where 1=1 ";这样写,后面所有的都可以加上and条件
5.多表查询,先把所有表写上,再找关系
select lx.fwlx fromTBL_JD jd,TBL_FWXX xx,TBL_FWLX lx where jd.jd = '亚运村'
6.如果是聚合函数,需要用uniqueResult来接收
int count =Integer.valueOf(query.uniqueResult().toString());
7.分页查询,设置setFirstResult和setMaxResults来处理,缺点就多的话占资源多。
int size = 3;
int page = 1;
int firstResultIndex = size*(page-1);
query.setFirstResult(firstResultIndex);
query.setMaxResults(size);
List<FWXX> list = query.list();
8.对象查询,Criteria 对象
Criteria c =session.createCriteria(FWXX.class); //创建Criteria 对象
if(fw.getTitle()!=null)
{c.add(Restrictions.like("title",fw.getTitle(),MatchMode.ANYWHERE));} //增加排除条件,le大于或者等于,ge小于或者等于,c.addOrder(Order.asc("fwlx.lxid"));增加排序条件,支持EL表达式获取对象的值,c.add(Restrictions.in("fwlx.lxid",aa));其中aa是object的数组
List<FWXX> list = c.list(); //获取值
9.sql查询,记得要跟实体挂钩.addEntity
String hql = "select * from PetInfo pii order by (pii.pet_cute + pii.pet_strength + pii.pet_love) desc";
Query query =session.createSQLQuery(hql).addEntity(PetInfo.class);
list =query.list();
10.用耦合方式存session可能有问题,在首页显示图书,尽量用解耦的方式
// HttpSession session =ServletActionContext.getRequest().getSession();
// session.setAttribute("bookLists",ListHelp.changeTitle(list));
Map map = ActionContext.getContext().getSession();
map.put("bookLists", ListHelp.changeTitle(list));