Hibernate查询常用方法总结
常用的查询方式
- 导航对象图检索方式:根据已经加载的对象,导航到其他对象,如关联对象的查询。
- OID检索方式:按照对象的OID来检索对象。get load
- HQL检索方式:使用专门的HQL查询接口和面向对象的HQL查询语言。
- QBC(Query By Criteria)检索方式:QBC提供的API来检索对象,这种API封装了基于字符串形式的查询语言,提供了更加面向对象的查询接口(了解开发中基本不用)。
- 本地SQL检索方式:这也是官方推荐的标准查询方式
1、使用HQL语句
1.1、说明
HQL语句 这一种是面向对象的查询查询方式,HQL查询提供了更加丰富的和灵活的查询特性,因此Hibernate将HQL查询方式立为官方推荐的标准查询方式,不仅提供了类似标准SQL语句的查询方式,还提供了面向对象的封装。在HQL查询中,语句from关键字后面跟的类名+类对象, where 后用对象的属性做条件;条件查询、分页查询、连接查询、嵌套查询,写起来与SQL语法基本一致,唯一不同的就是把表名换成了类或者对象。其它的,包括一些查询函数(count(),sum()等)、查询条件的设定等,全都跟SQL语法一样
1.2、HQL查询步骤:
- 获取Hibernate Session对象。
- 编写HQL语句。
- 以HQL语句作为参数,调用Session的createQuery方法创建查询对象。
- 如果HQL语句包含参数,调用Query的setXXX()方法为参数赋值。
- 调用Query对象的list等方法遍历查询结果
1.3、特点:
- 与SQL相似,SQL中的语法基本上都可以直接使用。
- SQL查询的是表和表中的列;HQL查询的是对象与对象中的属性。
- HQL的关键字不区分大小写,类名与属性名是区分大小写的。
- SELECT可以省略.但必须要使用别名
1.3、常用查询
1,简单的查询,Emp为实体名而不是数据库中的表名(面向对象特性)
hql = "FROM Emp";
hql = "FROM Emp AS e"; // 使用别名
hql = "FROM Emp e"; // 使用别名,as关键字可省略
2,带上过滤条件的(可以使用别名):Where
hql = "FROM Emp WHERE id<10";
hql = "FROM Emp e WHERE e.id<10";
hql = "FROM Emp e WHERE e.id<10 AND e.id>5";
3,带上排序条件的:Order By
hql = "FROM Emp e WHERE e.id<10 ORDER BY e.name";
hql = "FROM Emp e WHERE e.id<10 ORDER BY e.name DESC";
hql = "FROM Emp e WHERE e.id<10 ORDER BY e.name DESC, id ASC";
4,指定select子句(不可以使用select *)
hql = "SELECT e FROM Emp e"; // 相当于"FROM Emp e"
hql = "SELECT e.name FROM Emp e"; // 只查询一个列,返回的集合的元素类型就是这个属性的类型
hql = "SELECT e.id,e.name FROM Emp e"; // 查询多个列,返回的集合的元素类型是Object数组
hql = "SELECT new Emp(e.id,e.name) FROM Emp e"; // 可以使用new语法,指定把查询出的部分属性封装到对象中
5,执行查询,获得结果(list、uniqueResult、分页 )
Query query = session.createQuery("FROM Emp e WHERE id<3");
query.setFirstResult(0);//设置返回的结果集从第几条记录开始
query.setMaxResults(10); // 设置本次查询返回的结果数目 等同于 limit 0,10
//两种查询结果list、uniqueResult
// List list = query.list(); // 查询的结果是一个List集合
// Emp Emp = (Emp) query.uniqueResult();// 查询的结果是唯一的一个结果,当结果有多个,就会抛异常
6,方法链
List list = session.createQuery(//
"FROM Emp e")//
.setFirstResult(0)//
.setMaxResults(10)//
.list();
7,聚集函数:count(), max(), min(), avg(), sum()
hql = "SELECT COUNT(*) FROM Emp"; // 返回的结果是Long型的
hql = "SELECT min(id) FROM Emp"; // 返回的结果是id属性的类型
8,分组: Group By ... Having
hql = "SELECT e.name,COUNT(e.id) FROM Emp e GROUP BY e.name";
hql = "SELECT e.name,COUNT(e.id) FROM Emp e GROUP BY e.name HAVING count(e.id)>1";
hql = "SELECT e.name,COUNT(e.id) FROM Emp e WHERE id<9 GROUP BY e.name HAVING count(e.id)>1";
hql = "SELECT e.name,COUNT(e.id) " +
"FROM Emp e " +
"WHERE id<9 " +
"GROUP BY e.name " +
"HAVING count(e.id)>1 " +
"ORDER BY count(e.id) ASC";
hql = "SELECT e.name,COUNT(e.id) AS c " +
"FROM Emp e " +
"WHERE id<9 " +
"GROUP BY e.name " +
"HAVING count(e.id)>1 " + // 在having子句中不能使用列别名
"ORDER BY c ASC"; // 在orderby子句中可以使用列别名
9,连接查询 / HQL是面向对象的查询
内连接(inner关键字可以省略)
hql = "SELECT e.id,e.name,d.name FROM Emp e JOIN e.dept d";
hql = "SELECT e.id,e.name,d.name FROM Emp e INNER JOIN e.dept d";
左外连接(outer关键字可以省略)
hql = "SELECT e.id,e.name,d.name FROM Emp e LEFT OUTER JOIN e.dept d";
右外连接(outer关键字可以省略)
hql = "SELECT e.id,e.name,d.name FROM Emp e RIGHT JOIN e.dept d";
可以使用更方便的方法
hql = "SELECT e.id,e.name,e.dept.name FROM Emp e";
10,查询时使用参数
方式一:使用'?'占位
hql = "FROM Emp e WHERE id BETWEEN ? AND ?";
List list2 = session.createQuery(hql)//
.setParameter(0, 5)// 设置参数,第1个参数的索引为0。
.setParameter(1, 15)//
.list();
方式二:使用变量名
hql = "FROM Emp e WHERE id BETWEEN :idMin AND :idMax";
List list3 = session.createQuery(hql)
.setParameter("idMax", 15)
.setParameter("idMin", 5)
.list();
当参数是集合时,一定要使用setParameterList()设置参数值
hql = "FROM Emp e WHERE id IN (:ids)";
List list4 = session.createQuery(hql)
.setParameterList("ids", new Object[] { 1, 2, 3, 5, 8, 100 })
.list();
1,update与delete,不会通知Session缓存
Update
1.session.update()方法;
如果是只修改某一字段,使用HQL方式。
注:HQL语句不支持添加,但是Query支持添加。
int result = session.createQuery(//
"UPDATE Emp e SET e.name=? WHERE id>15")
.setParameter(0, "无名氏")//
.executeUpdate(); // 返回int型的结果,表示影响了多少行。
Delete
1.当删除一条数据时,直接使用session.delete()就可以
2.批量删除时,使用Hql形式,这是可以提高性能的方法,因为它中间省去了查询的步骤。
int result1 = session.createQuery(
"DELETE FROM Emp e WHERE id>15")
.executeUpdate(); // 返回int型的结果,表示影响了多少行。
1.4、通过构造方法进行属性查询
public List<Dept> getDeptByNameAndLoc(String deptName,String location){
Session session=HibernateUtil.getCurrentSession();
String hql="select new Dept( deptName,location) from Dept";
Query query=session.createQuery(hql);
List<Object[]> list2=query.list();
for (Object[] objects : list2) {
System.out.println(objects[0]+""+objects[1]);
}
return null;
1.5、子查询
查询有一个订单以上的客户。
from Customer c where 1<(select count(o) from c.orders o)
1.6,其他查询
String sql = "select new List(goodsid,goodsname,gibs) from goods ";
Query query = session.createQuery(sql);
List list = query.list();
返回List<Map<String,String>> list
String sql = "select new Map(goodsid,goodsname,gibs) from goods
返回List<Good> list
String sql = "select new Good(goodsid,goodsname,gibs) from goods ";
Query query = session.createQuery(sql);
List list = query.list();
2、QBC(Query By Criteria) 查询
说明
- 代表一次查询
- Criteria是一种比hql更面向对象的查询方式。Criteria 可使用 Criterion 和 Projection 设置查询条件。可以设置 FetchMode(联合查询抓取的模式 ) ,设置排序方式,Criteria 还可以设置 FlushModel (冲刷 Session 的方式)和 LockMode (数据库锁模式)。
- Criteria本身只是查询的容器。Criteria查询又称对象查询
- Criteria查询采用面向对象的方式封装查询条件。由Hibernater自动生成SQL查询语句
操作步骤
- 通过seesion的CreateCriteria()方法,创建一个Criteria对象
- 设置查询对象,name指对象的属性
- 把查询条件添加到Criteria对象中
- 执行list()查询返回结果。
核心接口说明
- Criteria 接口的核心方法
方法 说明 add() 增加一个代表查询条件的Criterion对象 addOrder() 增加一个代表排序的Criterion对象 createAlias() 创建关联查询,为所关联的持久化类建立别名 createCriteria() 在相互关联的持久化类之间建立条件约束 setFirstResult() 设定要获取的第一条记录的位置 setMaxResults() 设定要获取的记录的最大数量 list() 获取满足查询条件的记录的集合 uniqueResult() 获取满足查询条件的唯一记录 - QBC常用限定方法
方法 说明 Restrictions.eq 等于 Restrictions.allEq 参数为Map对象,使用key/value进行多个等于的比对,相当于多个Restrictions.eq 的效果 Restrictions.gt 大于 Restrictions.ge = 大于等于
Restrictions.lt < 小于 Restrictions.le <= 小于等于 Restrictions.between 对应SQL的between子句 Restrictions.like 对应SQL的LIKE子句 Restrictions.in 对应SQL的in子句 Restrictions.and and 关系 Restrictions.or or 关系 Restrictions.isNull 判断属性是否为空,为空则返回true 相当于SQL的 is null Restrictions.isNotNull 与isNull相反 相当于SQL的 is not null Restrictions.sqlRestriction SQL限定的查询 Order.desc 根据传入的字段进行降序排序 Order.asc 根据传入的字段进行升序排序 MatchMode.EXACT 字符串精确匹配.相当于”like ‘value’” MatchMode.ANYWHERE 字符串在中间匹配.相当于”like ‘%value%’” MatchMode.START 字符串在最前面的位置.相当于”like ‘value%’” MatchMode.END 字符串在最后面的位置.相当于”like ‘%value’”
案例
查询所有的员工
@Test public void list(){ List<Emp> empList = session.createCriteria(Emp.class).list(); for(Emp e : empList){ System.out.println(e.getEname()); } }
查询单个对象(使用 uniqueResult())
@Test public void uniqueResult(){ String hql = "from Emp where empno = 7369"; Emp emp = (Emp) HibernateUtil.getCurrentSession().createQuery(hql).uniqueResult(); }
like查询,忽略大小写
@Test public void likeQuery(){ List<Emp> empList = session.createCriteria(Emp.class).add(Restrictions.like("ename", "a", MatchMode.ANYWHERE).ignoreCase()).list(); for(Emp e : empList){ System.out.println(e.getEname()); } }
分页查询
@Test public void pageList(){ List<Emp> empList = session.createCriteria(Emp.class).setFirstResult(0).setMaxResults(4).list(); for(Emp e : empList){ System.out.println(e.getEname()); } }
@Test public void betweenQuery(){ List<Emp> empList = session.createCriteria(Emp.class).add(Restrictions.between("id", 7000, 8000)).list(); for(Emp e : empList){ System.out.println(e.getEname()); }
@Test public void inQuery(){ List<Emp> empList = session.createCriteria(Emp.class).add(Restrictions.in("id", new Integer[]{7369, 7499})).list(); for(Emp e : empList){ System.out.println(e.getEname()); } }
F.>或>=
//>= 或者 > @Test public void gtOrGeQuery(){ List<Emp> empList = session.createCriteria(Emp.class).add(Restrictions.ge("id", 7521)).list(); // 大于等于(>=) for(Emp e : empList){ System.out.println(e.getEname()); }
<或<=
@Test public void ltOrLeQuery(){ //List<Emp> empList = session.createCriteria(Emp.class).add(Restrictions.lt("id", 7500)).list(); // 小于(<) List<Emp> empList = session.createCriteria(Emp.class).add(Restrictions.le("id", 7521)).list(); // 小于等于(<=) for(Emp e : empList){ System.out.println(e.getEname()); } }
=查询
//= @Test public void eqQuery(){ List<Emp> empList = session.createCriteria(Emp.class).add(Restrictions.eq("id", 7521)).list(); // 等于(=) for(Emp e : empList){ System.out.println(e.getEname()); } }
多条件查询(and)
//多条件查询and @Test public void multiAndQuery(){ String beginDateStr = "1980-07-26 00:00:00"; String endDateStr = "2016-07-28 23:59:59"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); Date beginDate = null; Date endDate = null; try { beginDate = sdf.parse(beginDateStr); endDate = sdf.parse(endDateStr); } catch (ParseException e) { e.printStackTrace(); } List<Emp> empList = session.createCriteria(Emp.class) .add(Restrictions.ge("id", 7521)) .add(Restrictions.between("hiredate", beginDate, endDate)) .add(Restrictions.like("ename", "a", MatchMode.ANYWHERE).ignoreCase()) .list(); for(Emp e : empList){ System.out.println(e.getEname()); } }
多条件查询(or)
//多条件或者查询 @Test public void multiOrQuery(){ List<Emp> empList = session.createCriteria(Emp.class) .add(Restrictions.or(Restrictions.eq("id", 7521), Restrictions.like("ename", "A%").ignoreCase())) .list(); for(Emp e : empList){ System.out.println(e.getEname()); } }
排序
@Test public void orderQuery(){ List<Emp> empList = session.createCriteria(Emp.class).addOrder(Order.desc("salary")).list(); for(Emp e : empList){ System.out.println(e.getEname()); } }
统计
//统计20号部门有多少人 @Test public void countQuery(){ List<Integer> list = session.createCriteria(Emp.class).setProjection(Projections.rowCount()).add(Restrictions.eq("dept.id", 20)).list(); System.out.println(list.get(0)); }
统计
//统计各个部门的人数、工资的平均值、工资的最大值、工资的最小值、工资的总和 @Test public void count(){ List<Object[]> list = session.createCriteria(Emp.class) .setProjection(Projections.projectionList() .add(Projections.property("dept.id")) .add(Projections.rowCount()) .add(Projections.avg("salary")) .add(Projections.max("salary")) .add(Projections.min("salary")) .add(Projections.sum("salary")) .add(Projections.groupProperty("dept.id")) ).list(); for(Object[] obj : list){ for(Object o : obj){ System.out.print(o + " "); } System.out.println(); } }
投影(多列)
//只查询工号和姓名 @Test public void nameAndNoQuery(){ List<Object[]> list = session.createCriteria(Emp.class) .setProjection( Projections.projectionList() .add(Projections.property("ename")) .add(Projections.property("id")) ).list(); for(Object[] obj : list){ for(Object o : obj){ System.out.print(o + " "); } System.out.println(); } }
非空查询
//非空查询 @Test public void notNullQuery(){ List<Emp> list = session.createCriteria(Emp.class).add(Restrictions.isNotNull("comm")).list(); for(Emp e : list){ System.out.println(e.getEname()); } }
2、本地sql查询
HQL查询并不能涵盖所有的查询特性,一些复杂的查询还必须借助sql达到期望的目标,也就是本地sql,使用query.createSQLQuery(String sql)方法,同时使用addEntity()方法将别名与实体类关联起来
//查询每个员工的领导所在部门的信息
String sql= "select * from (select e1.empno,e1.ename,e1.mgr mno,e2.ename mname,e2.deptno from emp e1 join emp e2 on e1.mgr=e2.empno) t join dept on t.deptno=dept.deptno"
Query query = this.getSession().createSQLQuery(sql).addEntity(Emp.class);
List<Emp> result = query.list();