4.1基本查询HQL(Hibernate Query Language)
这是 Hibernate 官方所推荐的查询语言,接近 SQL 的语法,并提供更多的特性与封装。
使用HQL查询最简单的例子,就是查询指定类别对应表格的所有数据,例如:
Session session = sessionFactory.openSession();
Query query = session.createQuery("from User");
List names = query.list();
Iterator iterator = names.iterator();
while(iterator.hasNext()) {
User user = (User) iterator.next();
System.out.println(user.getId() + "\t" +
user.getAge() + "\t" +
user.getName());
}
也可以指定类别的全名,例如:
Query query = session.createQuery("from onlyfun.caterpillar.User");
HQL本身不区分大小写,不过要注意类别的名称必须区分大小写。
在查询类别对应的表格时,需注意到继承的问题,Hibernate会自动判定继承关系,如果查询的类别是某类别的父类别,则会返回与父类别、子类别对应的所有表格数据,例如如果查询java.lang.Object,由于Object在Java中是所有类别的父类别,所以下面这个查询会返回数据库中所有表格的数据:
Query query = session.createQuery("from java.lang.Object");
如果要针对某个属性作查询,则可以如下:
Session session = sessionFactory.openSession();
Query query = session.createQuery("select user.name from User as user");
List names = query.list();
Iterator iterator = names.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
如果要查询两个以上的属性,则如下,查询的结果会以数组的方式传回:
Session session = sessionFactory.openSession();
Query query = session.createQuery("select user.age, user.name from User as user");
List names = query.list();
Iterator iterator = names.iterator();
while(iterator.hasNext()) {
Object[] obj = (Object[]) iterator.next();
System.out.println(obj[0] + "\t" + obj[1]);
}
如果User类别提供有适当的建构方法,则可以在使用HQL时直接指定新建一个对象传回,例如若User如下设计:
package onlyfun.caterpillar;
public class User {
private Integer id;
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
....
}
则在使用HQL查询时可以如下:
Session session = sessionFactory.openSession();
Query query = session.createQuery("select new User(user.name, user.age) from User as user");
List names = query.list();
Iterator iterator = names.iterator();
while(iterator.hasNext()) {
User user= (User) iterator.next();
System.out.println(user.getAge() + "\t" + user.getName());
}
要注意的是,这个返回的User实例并未与数据库有任何关联,可以试着取得id属性,可以发现它的值是nul,如果试图使用Session的saveOrupdate()方法,则会新增一笔数据而不是更新原有的数据。
可以使用distinct去除数据重复的记录:
Query query = session.createQuery("select distinct user.age from User as user");
List names = query.list();
Iterator iterator = names.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
您也可以在HQL中使用函式,例如取得资料的笔数:
Query query = session.createQuery("select count(*) from User as user");
List names = query.list();
Iterator iterator = names.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
使用avg()取得属性的平均值:
Query query = session.createQuery("select avg(user.age) from User as user");
List names = query.list();
Iterator iterator = names.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
使用upper()函式将字符串转为大写:
Query query = session.createQuery("select upper(user.name) from User as user");
List names = query.list();
Iterator iterator = names.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
可以一并参考 Query 的使用。
4.2 where、group by、order by 子句
可以使用where子句来限定查询的条件,除了 = 运算之外,还有 >、>=、<、<=、!= 或 <>等比较运算,例如:
Session session = sessionFactory.openSession();
Query query = session.createQuery("from User user where user.name='caterpillar'");
List names = query.list();
Iterator iterator = names.iterator();
while(iterator.hasNext()) {
User user = (User) iterator.next();
System.out.println(user.getAge() + "\t" + user.getName());
}
也可以在where子句上进行表达式,例如:
Query query = session.createQuery("from User user where (user.age / 10 = 3)");
也可以在where子句上使用and、or,例如:
Query query = session.createQuery("from User user where (user.age > 20) and (user.name = 'caterpillar')");
is not nullL与is null则可以测试字段值是否为空值,例如:
Query query = session.createQuery("from User user where user.name is not null");
between可以测试字段值是否在指定的范围之内,例如:
Query query = session.createQuery("from User user where user.age between 20 and 30");
可以使用in或not in来测试字段值是否在您指定的集合中,例如:
Query query = session.createQuery("from User user where user.name in('caterpillar', 'momor')");
like或not like可以让您进行模糊条件搜寻,例如想搜寻名称中含有cater开头的数据:
Query query = session.createQuery("from User user where user.name like 'cater%'");
可以对查询结果使用order by进行排序:
Query query = session.createQuery("from User user order by user.age");
可使用desc反排序:
Query query = session.createQuery("from User user order by user.age desc");
可同时指定两个以上的排序方式,例如先按照"age"反序排列,如果"age"相同,则按照"name"顺序排列:
Query query = session.createQuery("from User user order by user.age desc, user.name");
可以配合GROUP BY子句,自动将指定的字段依相同的内容群组,例如依字段"sex"分组并作平均:
Query query = session.createQuery("select user.sex, avg(user.age) from User user group by user.sex");
一个执行的结果如下:
+-------------------------------+
| sex | avg(age) |
+-------------------------------+
| male | 30 |
+-------------------------------+
| female | 25 |
+-------------------------------+
还可以结合having子句,例如只将平均大于20的数据分组显示出来:
Query query = session.createQuery("select user.sex, avg(user.age) from User user group by user.sex having avg(user.age) > 20");
4.3更新、删除
在Hibernate 2时,HQL只用于查询数据,要更新或删除数据,则是依赖于Session的update()、saveOrUpdate()、delete()等方法,在Hibernate 3中,HQL新增了update与delete语句,可以直接使用HQL指定更新或删除,例如使用update子句进行更新:
Session session = sessionFactory.openSession();
Transaction tx= session.beginTransaction();
Query query = session.createQuery("update User set name='momor' where name='bbb'");
query.executeUpdate();
tx.commit();
session.close();
使用delete子句进行数据删除:
Session session = sessionFactory.openSession();
Transaction tx= session.beginTransaction();
Query query = session.createQuery("delete User where name='bush'");
query.executeUpdate();
tx.commit();
session.close();
5.SQL 支援
Hibernate 提供了对 SQL 的支持,并可以自行定义持久化方式。
5、1建立 SQL 查询
Hibernate提供了对SQL的支持,您可以指定您所要建立的SQL,并将实体类别与数据表格关联,举个例子来说,如果您打算使用像以下的SQL语句:
SELECT * FROM user WHERE age > 20
则您可以如下建立SQL查询:
// SQL,并指定别名为user
String sql = "select {user.*} from User user where user.age > 20";
Session session = sessionFactory.openSession();
// 建立 SQLQuery
SQLQuery sqlQuery = session.createSQLQuery(sql);
// 将别名user与实体类User关联在一起
sqlQuery.addEntity("user", User.class);
Iterator iterator = sqlQuery.list().iterator();
while(iterator.hasNext()) {
User user = (User) iterator.next();
System.out.println(user.getAge() + "\t" + user.getName());
}
session.close();
addEntity()是将实体类别与别名连结在一起的方法,大括号指定要查询的数据,Hibernate根据所给定的SQL自动生成以下的句子:
select user.id as id0_, user.name as name0_0_, user.age as age0_0_ from User user where user.age > 20
返回的结果则由Hibernate进行封装为所指定别名关联之实体类,如此您可以得到使用SQL的弹性,但无需处理繁琐的ResultSet。
您也可以将SQL语句定义在映像文件中,例如:
User.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="onlyfun.caterpillar.User" table="user....
</class>
<sql-query name="onlyfun.caterpillar.QueryUser">
<![CDATA[
select {user.*} from User user where user.age > 20
]]>
<return alias="user" class="onlyfun.caterpillar.User"/>
</sql-query>
</hibernate-mapping>
定义的时候,使用<return>卷标指定别名与实体类之关联,配合映像文件中的定义,您可以如下运行Hibernate:
Session session = sessionFactory.openSession();
Query query = session.getNamedQuery("onlyfun.caterpillar.QueryUser");
Iterator iterator = query.list().iterator();
while(iterator.hasNext()) {
User user = (User) iterator.next();
System.out.println(user.getAge() + "\t" + user.getName());
}
session.close();
也可以设定查询参数,例如:
....
<sql-query name="onlyfun.caterpillar.QueryUser">
<![CDATA[
select {user.*} from User user where user.age > :age
]]>
<return alias="user" class="onlyfun.caterpillar.User"/>
</sql-query>
....
使用Hibernate查询时如下:
Session session = sessionFactory.openSession();
Query query = session.getNamedQuery("onlyfun.caterpillar.QueryUser");
query.setInteger("age", 20);
Iterator iterator = query.list().iterator();
while(iterator.hasNext()) {
User user = (User) iterator.next();
System.out.println(user.getAge() + "\t" + user.getName());
}
session.close();
5.2自定义 insert、update、delete
Hibernate 3的映射文件中新增了<sql-insert>、<sql-update>与<sql-delete>三个标签,您可以在这三个标签中使用SQL自定义您的INSERT、UPDATE、DELETE,也就是储存、更新、删除数据时的行为,例如:
User.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="onlyfun.caterpillar.User" table="user">
<id name="id" column="id" type="java.lang.Integer">
<generator class="native"/>
</id>
<property name="name" column="name" type="java.lang.String"/>
<property name="age" column="age" type="java.lang.Integer"/>
<sql-insert>
INSERT INTO user (name, age) VALUES (?, ?)
</sql-insert>
<sql-update>
UPDATE user SET name=?, age=?, WHERE id=?
</sql-update>
<sql-delete>
DELETE FROM user WHERE id=?
</sql-delete>
</class>
</hibernate-mapping>
? (参数) 对应的顺序是映像文件中属性出现的顺序,假设您储存对象:
session = sessionFactory.openSession();
tx = session.beginTransaction();
session.save(user);
tx.commit();
session.close();
则执行结果中显示的SQL语句会是您自定义的语句,而不是由Hibernate自动生成的语句:
Hibernate:
INSERT INTO user (name, age) VALUES (?, ?)