Hibernate查询(HQL——Hibernate Query Language)
HQL查询
HQL提供了是十分强大的功能,它是针对持久化对象,用取得对象,而不进行update,delete和insert等操作。而且HQL是面向对象的,具备继承,多态和关联等特性。
from子句:
from子句是最简单的HQL,例如from Student,也可以写成 select s from Student s。它简单的返回Student类的所有实例。值得注意的是除了JAVA类和属性的名称外,HQL语句对大小写不敏感。
select子句:
有时并不需要取得对象的所有属性,这时可以使用select子句进行属性查询,如select s.name from Student s。
统计函数查询
可以在HQL中使用函数,经常使用的函数如下:
count():统计记录条数。
min():求最小值。
max():求最大值。
sum():求和。
avg():求平均值。
例,要取得Student实例的数量,可以编写如下HQL语句:
select count(*) from Student
取得Student平均年龄的HQL语句:
select avg(s.age) from Student as s
可以使用distinct去除重复的数据:
select distinct s.age from Student as s
where子句:
HQL也支持子查询,它通过where子句实现这一机制。where子句可以让用户缩小要返回的实例的列表范围。例如下面语句会返回所有名字为"Bill"的Student实例:
Query query = session.createQuery("from Student as s where s.name='Bill'");
where子句允许出现的表达式包括了SQL中可以使用的大多数情况。
常用操作符
数学操作:+,-,*,/
真假比较操作:=, >=, <=, <>, !=, like
逻辑操作:and ,or, not
字符串连接:||
SQL标题函数 :如upper()和lower()
如果查询返回多条记录,可以用以下关键字来量化
all:表示所有的记录。
any:表示所有记录中的任意一条。
some:与any相同。
in:与any等价。
exists:表示子查询至少要返回一条记录。
例如,下面语句返回所有学生年龄都大于18的班级对象
from Group g where 18<all (select s.age from g.students s)
下列语句返回在所有学生中有一个学生的年龄等于22的班级:
from Group g where 22 = any (select s.age from g.students s)
或者
from Group g where 22= some(select s.age from g.students s)
或者
from Group g where 22 in (select s.age from g.students s)
连接查询
与SQL一样,HQL也支持连接查询,如内连接,外连接和交叉连接:
inner join:内连接
left outer join:左外连接
rigth outer join:右外连接
full join:全连接,但不常用
order by子句
查询返回列表可以按照任何返回的类或者组件的属性排序
from Student s order by s.name asc
Criteria Query方式
当查询数据时,往往需要设置查询条件。在SQL或HQL语句中,查询条件常常放在where子句中。此处Hibernate还支持Criteria查询,这种查询方式把查询条件封装为一个Criteria对象。在实际应用中,可以使用Session的createCriteria()方法构建一个org.hibernate.Criteria实例,然后把具体的查询条件通过Criteria的add方法加入到Criteria实例中。这样程序员可以在不使用SQL甚至HQL的情况下进行数据查询。
常用的查询限制方法
代码中 Restrictions.eq()方法表示equal,即等于的情况。Restrictions类提供了查询限制机制。它提供了许多方法,以实现查询限制
Restrictions.eq():equal,=
Restrictions.allEq(): 参数为Map对象,使用key/value进行多个等于的对比,相当于多个Restrictions.eq()的效果
Restrictions.gt():greater-than: >
Restrictions.lt():less-than:<
Restrictions.le:less-equal:<=
Restrictions.between():对应SQL的between子句。
Restrictions.like():对应SQL的like子句。
Restrictions.in():对应SQL的in子句。
Restrictions.and():and 关系。
Restrictions.or():or 关系。
Restrictions.isNull():判断属性是否为空,为空返回true,否则返回false。
Restrictions.isNoyNull():与上面的相反。
Order.asc():根据传入的字段进行升序排序。
Order.desc():与上相反
MatchMode.EXACT:字符串中精确匹配,相当于like 'value'
MatchMode.ANYWHERE:字符串在中间位置,相当于like'%value%'
MatchMode.START:字符串在最前面,相当于like'value%'
MatchMode.END:字符串在最后,相当于like'%value'
下面是几个查询限制的例子:
查询学生名字以t开关的所有Student对象
Criteria criertia = session.createCriteria(Student.class); criteria.add(Restrictions.like("name", "t%"));
List list = criteria.list(); Student stu = (Student)list.get(0);
或者:
Criteria criertia = session.createCriteria(Student.class); criteria.add(Restrictions.like("name", "t",MatchMode.START)); List list = criteria.list(); Student stu = (Student)list.get(0);
查询学生姓名在Bill,Jack和Tom之间所有的Student对象
String[] names = {"Bill","Jack","Tom"}; Criteria criertia = session.createCriteria(Student.class); criteria.add(Restrictions.in("name", names)); List list = criteria.list(); Student stu = (Student)list.get(0);
查询学生年龄(age)等于22或为空(null)的所有学生对象
Criteria criertia = session.createCriteria(Student.class); criteria.add(Restrictions.eq("age", new Integer(22))); criteria.add(Restrictions.isNull("age")); List list = criteria.list(); Student stu = (Student)list.get(0);
查询学生姓名以字母F开头的所有Student对象,并按姓名升序排序
Criteria criertia = session.createCriteria(Student.class); criteria.add(Restrictions.like("name", "F%")); criteria.addOrder(Order.asc("name")); List list = criteria.list(); Student stu = (Student)list.get(0);
注意调用Order.asc的方法应该是Criteria.addOrder()方法。
连接限制
Criteria查询中使用FetchMode来实现连接限制。在HQL语句中,可以通过fetch关键字来表示预先抓取(Eager fetching),如下:
from Group g
left join fetch g.students s
where g.name like '%2005'
可以使用Criteria的API完成同样的功能
Native SQL查询
本地SQL查询指的是直接使用本地数据库的SQL语言进行查询。这样做对于将原来的SQL/JDBC程序迁移到Hibernate应用很有用。创建一个基于SQL的Query Native SQL查询是通过SQLQuery接口来控制的,它通过调用Session.createSQLQuery()方法来获得。
命名SQL查询
与HQL的命名查询相似,也可以将 本地的SQK查询语句定义在映射文件中,然后像调用一个命名HQL查询一样专题报道调用命名SQL查询。
Hibernate中Session接口
1、Session的save()和persist()方法
Session的save()方法使一个临时对象转变为持久化对象。它完成以下操作:
(1)将临时对象加入到Session缓存中,使其进入持久化状态。
(2)选用映射文件指定的标识符生成器,为持久化对象分配唯一的OID。
(3)计划执行一个insert语句。
Session的save()方法是用来持久化临时对象的。不应将持久化对象或游离对象传递给save()方法。若将持久化对象传递给save()方法,则该步保存操作是多余的。若将游离对象传递给save()方法,则会重新生成OID,再保存一次。
Session的persist()方法与save()方法类似,也能将临时对象转变为持久化对象。
persist()方法与save()方法的区别在于:persist()方法不保证立即为持久化对象的OID赋值,而是有可能在Session清理缓存的时候才为OID赋值。此外,如果是在事物边界以外调用persist()方法,则该方法不会计划执行insert语句。而save()方法不论是在事物边界以外还是以内,都会计划执行insert语句。
2、Session的load()与get()方法
Session的load()与get()方法都能从根据给定的OID从数据库中加载一个持久化对象,这两个方法的区别在于:
(1)当数据库中不存在与OID对应的记录时,load()方法抛出org.hibernate.ObjectNotFoundException异常,而get()方法返回为null。
(2)load方法采用配置的加载策略(默认为延迟加载),而get()方法则会忽略配置,总是采用立即加载方法。
3、Session的update()方法
Session的update()方法使一个游离对象转变为持久化对象。它完成以下操作:
(1)将游离对象加入到Session缓存中,使其转变为持久化对象。
(2)计划执行一个update语句。
当update()方法关联一个游离对象时,若在Session的缓存中已存在相同的OID的对象时,会抛出异常。
4、Session的saveOrUpdate()方法
Session的saveOrUpdate()方法同时包含了save()方法与update()方法的功能,如果传入的参数是临时对象,就调用save()方法;如果传入的参数是游离对象,就调用update()方法。HIbernate根据对象的OID,version版本属性等来判断参数是临时对象还是游离对象。
5、Session的merge()方法
Session的merge()方法能够将一个游离对象的属性复制到一个持久化对象中。其处理流程如下:
(1)根据游离对象的OID到Session缓存中查找匹配的持久化对象。若找到匹配的持久化对象,则将游离对象的属性复制到持久化对象中,计划实行一条update语句,然后返回持久化对象的引用。
(2)如果在Session的缓存中没有找到与游离对象OID一致的持久化对象,那么就试图根据该OID从数据库中加载持久化对象。如果数据库中存在匹配的持久化对象,则将游离对象的属性复制到刚加载的持久化对象中,计划实行一条update语句,然后返回持久化对象的引用。
(3)如果数据库中也不存在or对象是临时对象时,则会新建一个对象,将属性赋值到该新建对象中,再持久化新建对象,最后返回新建对象的引用。
merger()和saveOrUpdate()的区别:调用完meger()对象仍然是脱管状态。
6、Session的delete()方法
Session的delete()方法用于从数据库中删除一个java对象。delete()方法既可以删除持久化对象,也可以删除游离对象。其处理过程如下:
(1)如果传入的参数是游离对象,则先使游离对象与Session关联,使它变为持久化对象。如果参数是持久化对象,则忽略该步。
(2)计划执行一个delete语句。
(3)把对象从Session缓存中删除,该对象进入删除状态。
7、Session的replicate()方法
Session的replicate()方法能够将一个数据库中的对象复制到另一个数据库中。
Hibernate检索策略
简介: Hibernate的Session在加载一个Java对象时,可以将与这个对象相关联的其他Java对象都加载到缓存中,以便程序及时调用。但有些情况下,我们不需要加载太多无用的对象到缓存中,一来这样会撑爆内存,二来增加了访问数据库的次数。所以为了合理的使用缓存,Hibernate提供了几种检索策略来供用户选择。
种类:立即检索策略、延迟检索策略、左外连接检索策略
1、立即检索策略
采用立即检索策略,会将被检索的对象,以及和这个对象关联的一对多对象都加载到缓存中。Session的get方法就使用的立即检索策略。
优点:频繁使用的关联对象能够被加载到缓存中。
缺点:1、占用内存。2、Select语句过多。
2、延迟检索策略
采用延迟检索策略,就不会加载关联对象的内容。直到第一次调用关联对象时,才去加载关联对象。在不涉及关联类操作时,延迟检索策略只适用于Session的load方法。涉及关联类操作时,延迟检索策略也能够适用于get,list等操作。在类级别操作时, 延迟检索策略,只加载类的OID不加载类的其他属性,只用当第一次访问其他属性时,才回访问数据库去加载内容。(这里使用了CGLIB生成了类的代理类)在关联级别操作时,延迟检索策略,只加载类本身,不加载关联类,直到第一次调用关联对象时,才去加载关联对象程序模式都是用延迟加载策略。如果需要指定使用延迟加载策略。在配置文件中设置<class>的lazy=true,<set>的lazy=true或extra(增强延迟)<many-to-one>的lazy=proxy和no-proxy。
优点:由程序决定加载哪些类和内容,避免了大量无用的sql语句和内存消耗。
缺点:在Session关闭后,就不能访问关联类对象了。 需要确保在Session.close方法前,调用关联对象。
3、左外连接检索策略
采用左外连接检索,能够使用Sql的外连接查询,将需要加载的关联对象加载在缓存中。
<set>fetch设置为join,<many-to-one>的fetch设置为 join
优点:对应用程序完全透明,不管对象处于持久化状态,还是游离状态,应用程序都可以方便的从一个对象导航到与它关联的对象。2.使用了外连接,select语句数目少。
缺点:可能会加载应用程序不需要访问的对象,白白浪费许多内存空间。2.复杂的数据库表连接也会影响检索性能。
batch-size属性:
无论是立即检索还是延迟检索,都可以指定关联查询的数量,这就需要使用batch-size属性来指定,指定关联查询数量,以减少批量检索的数据数目。