完成Hibernate 对象查询语言 HQL 实验 - Finished tests with Hibernate Query Language
"select c.name, count(s) from Student s join s.classes c " + "group by c.name order by c.name"
很有意思吧,其中Student是对象哦,不是表。
刚才完成了关于 Hibernate中 HQL [一个类似于sql语法的] 的实验。
hql很强大,很好用,也很对象。
现在喜欢把概念,管它什么东西都画成图,画图后就清楚了很多。每天画几幅图,感觉小时候真应该去学画画和文科。><
所以以后编程的时候就在参考图,没办法,无数学头脑。
hql 用起来的感觉,很像在 传统的sql 语句中 把每个表,每个field,换成是面向对象世界中的 实体和 实体.引用实体.属性。
本质很简单,到头来,他们全部都是 sql, 只是 hibernate 把sql的感觉 包装成了 对象的感觉。
也就是你写一个hql,然后hibernate按照规则,把你写的hql 转成 sql,向数据库发, and vise versa.
hql主题包含 11 大点,每天有很多小细节,每个小细节构成一个小实验。实验的数据都是 “学生和班级”模型。
真实情况下,差不太多,所有的对象无非就是各种对象组成的,比如学生和班级 是典型的 双N-1 关系。
有些细节比如:
1. method chain programming convention
2. 如果处理 日期
3. 处理 ? ,很重要,因为查询条件都是由 用户从网络另一段通过 页面 html过来的。
4. 如何处理 范围, 分组, 排序。重要,因为用户天天就在做这些。
-----------------------------------------------------------------
以下是知识点部分。
hibernate查询语言hql
在hql中关键字不区分大小写,但是属性和类名区分大小写
1、简单属性查询【重要】
* 单一属性查询,返回结果集属性列表,元素类型和实体类中相应的属性类型一致
* 多个属性查询,返回的集合元素是对象数组,数组元素的类型和对应的属性在实体类中的类型一致
数组的长度取决与select中属性的个数
* 如果认为返回数组不够对象化,可以采用hql动态实例化Student对象。首先在Student类中构建一个constructor - Student(id, name),然后就可以在下面使用,amazing,此时返回的 list中为Student对象集合
参见:SimplePropertyQueryTest.java
2、实体对象查询【重要】
* N + 1问题,在默认情况下,使用query.iterate查询,有可以能出现N+1问题
所谓的N+1是在查询的时候发出了N+1条sql语句
1: 首先发出一条查询对象id列表的sql
N: 根据id列表到缓存中查询,如果缓存中不存在与之匹配的数据,那么会根据id发出相应的sql语句
* list和iterate的区别?
* list每次都会发出sql语句,list会向缓存中放入数据,而不利用缓存中的数据
* iterate:在默认情况下iterate利用缓存数据,但如果缓存中不存在数据有可以能出现N+1问题
参见:SimpleObjectQueryTest1.java/SimpleObjectQueryTest2.java
-hiberanate session和 cpu的 一级cache绑定,就是看一级cache又没有数据,没有就发sql
-Query的 Iterator 接口使用缓存
-通过执行一次list(),一次iterator()消除N+1问题
-如果执行2次list(),虽然第一次数据已经在first level cache,但是list()还是会重新发sql,因为list()只往cache中放数据,但是不会利用cache.
3、条件查询【重要】
* 可以采用拼字符串的方式传递参数
* 可以采用 ?来传递参数(索引从0开始),注意使用“方法chain”编程
-List students = session.createQuery("select s.id, s.name from Student s where s.name like ?") .setParameter(0, "%1%")
.list();
* 可以采用 :参数名 来传递参数 – 如:myname
* 如果传递多个参数,可以采用setParamterList方法
* 在hql中可以使用数据库的函数,如:date_format
-"select s.id, s.name from Student s where date_format(s.createTime, '%Y-%m')=?" 查询比如2008年2月注册的学生
-List students = session.createQuery("select s.id, s.name from Student s where s.createTime between ? and ?")
.setParameter(0, sdf.parse("2008-01-10 00:00:00"))
.setParameter(1, sdf.parse("2008-02-15 23:59:59"))
.list(); 查询在2个时间点之间注册的学生
参见:SimpleConditionQueryTest.java
4、hibernate也支持直接使用sql进行查询
-List students = session.createSQLQuery("select * from t_student").list();
以前的项目常使用hibernate和jdbc/sql/dao混杂的编程,对于效率问题
参见:SqlQueryTest.java
5、外置命名查询
* 在映射文件中采用<query>标签来定义hql
* 在程序中采用session.getNamedQuery()方法得到hql查询串
-session.getNamedQuery("searchStudents").setParameter(0, 10)
.list()
参见:Student.hbm.xml、NameQueryTest.java
6、查询过滤器 – 知道就行,用的时候再去查;
* 在映射文件中定义过滤器参数
* 在类的映射中使用这些参数
* 在程序中启用过滤器
-用途比如 过滤登陆用户输入的内容,过滤其他人,其实就是传入自己的id
参见:Student.hbm.xml、FilterQueryTest.java
7、分页查询【很重要】
* setFirstResult(),从0开始
* setMaxResults,每页显示多少条数据
-List students = session.createQuery("from Student")
.setFirstResult(1)
.setMaxResults(2)
.list();
参见:PageQueryTest.java
8、对象导航查询,在hql中采用 . 进行导航【重要】
-List students = session.createQuery("select s.name from Student s where s.classes.name like '%1%'").list();
参见:ObjectNavQueryTest.java
9、连接查询【重要】on … = … condition
* 内连
* 外连接(左连接/右连接)
-普通内连"select c.name, s.name from Student s inner join s.classes c"
对应sql: Hibernate: select classes1_.name as col_0_0_, student0_.name as col_1_0_ from t_student student0_ inner join t_classes classes1_ on student0_.classesid=classes1_.id
-左外连接"select c.name, s.name from Classes c left join c.students s"
Hibernate: select classes0_.name as col_0_0_, students1_.name as col_1_0_ from t_classes classes0_ left outer join t_student students1_ on classes0_.id=students1_.classesid
-右边外连接"select c.name, s.name from Classes c right join c.students s"
Hibernate: select classes0_.name as col_0_0_, students1_.name as col_1_0_ from t_classes classes0_ right outer join t_student students1_ on classes0_.id=students1_.classesid
参见:JoinQueryTest.java
10、统计查询【重要】但较少用hibernate做统计,主要是用一些市场上专门做报表的中间件。
-"select count(*) from Student" hql中可以使用sql函数
-"select c.name, count(s) from Student s join s.classes c " + "group by c.name order by c.name" 计算每个班多少学生,inner join
参见:StatQueryTest.java
11、DML风格的操作,批量操作(尽量少用,因为和缓存不同步)
-"update Student s set s.name=? where s.id < ?"
参见:DMLQueryTest.java
- reference to sxt's source package and doc
- time consumed in this update : 10 mins