1.Hibernate的检索方式
1.1通过对象导航
根据已经加载的对象导航到其他对象。
Customer c1 = new Customer("张三");
Ordero1 = new Order("N001");
Ordero2 = new Order("N002");
Ordero3 = new Order("N003");
/*
* o1关联c1,而c1没有关联o1
* c1关联o2,o3,而o2,o3没有管关联c1
* 两个域对象的映射文件都有cascade="save-update"属性
* session.save(c1) 插入几条记录? 3
* session.save(o1) 插入几条记录? 4
* session.save(o2) 插入几条记录? 1
*/
//o1单向关联c1
o1.setCustomer(c1);
//c1单向关联o2和o3
c1.getOrders().add(o2);
c1.getOrders().add(o3);
// session.save(c1);//3条,c1,o2,o3被保存了
// session.save(o1);//4条,o1,c1,o2,o3都被保存了
session.save(o2);//1条,o2被保存了
1.2通过session.get(Xxx.class, id)方法和session.load(Xxx.class, id)方法
按照对象的 OID 来检索对象。
eg:
Order order =(Order)session.get(Order.class, 1);
Order order = (Order)session.load(Order.class,1);
1.3使用面向对象的 HQL 查询语言
HQL(HibernateQuery Language) 是面向对象的查询语言, 它和 SQL 查询语言有些相似. 在 Hibernate 提供的各种检索方式中, HQL 是使用最广的一种检索方式. 它有如下功能:
A在查询语句中设定各种查询条件
B支持投影查询, 即仅检索出对象的部分属性
C支持分页查询
D支持连接查询
E支持分组查询, 允许使用 HAVING 和 GROUP BY 关键字
F提供内置聚集函数, 如 sum(), min()和 max()
G支持动态绑定参数
HQL和SQL的关系:
1.HQL 查询语句是面向对象的, Hibernate 负责解析 HQL 查询语句, 然后根据对象-关系映射文件中的映射信息, 把 HQL 查询语句翻译成相应的 SQL 语句. HQL 查询语句中的主体是域模型中的类及类的属性。
2.SQL 查询语句是与关系数据库绑定在一起的. SQL 查询语句中的主体是数据库表及表的字段.。
注意:使用HQL语言查询数据库时,是不会出现表中的字段和表名的,只有类名和类的属性出现,sql的关键字是可以出现的。
常用HQL语句:
FROMCustomer 简单查询
/*//简单查询,查询所有客户
Stringhql = "FROM Customer"; //关键字from+类名
Queryquery = session.createQuery(hql);
List<Customer>customers = query.list();
for(Customer c : customers) {
System.out.println(c.getName());
}
FROMCustomer AS c WHERE c.name = ? query.setString(0,"张三") 根据名字查询
FROMCustomer AS c WHERE c.name = :name query.setString("name","张三")
/*
* 根据名字查询客户
* from + 类名 [as] 别名 where 别名.属性名= ?/:xx
* 如果要根据id查询客户可以直接使用session.get(Customers.class, 1)
*/
/*// Stringhql = "FROM Customer AS c WHERE c.name = ?";
Stringhql = "FROM Customer AS c WHERE c.name = :name"; //as可省略
Queryquery = session.createQuery(hql);
// query.setString(0,"张三");//为占位符?赋值,索引从0开始,jdbc的从1开始
query.setString("name","张三");//冒号:后面的名字任何,可以为:xx,:yy等等,赋值时只要写名字就可以了,冒号不必写
Customerc = (Customer) query.uniqueResult();//因为根据名字查询的结果只用一条,无需用集合接收
System.out.println(c.getName());*/
FROMjava.lang.Object 多态查询
/*
* 多态查询(是指查询出当前类及所有子类的实例)
*/
/* Stringhql = "FROM java.lang.Object"; //这里要写全类名,否则在当前映射文件指定的包下找不到Object类会出错。
Queryquery = session.createQuery(hql);
List<Object[]> objects = query.list();//返回List集合,里面装了Object数组,数组的元素为客户和订单
for (Object o : objects) {
if(oinstanceof Customer) {
Customerc = (Customer) o;
System.out.println(c.getName());
}else if(o instanceof Order) {
Orderorder = (Order) o;
System.out.println(order.getOrderNum());
}
}*/
FROMOrder o ORDER BY o.id DESC 排序
//对查询结果进行排序
/* Stringhql = "FROM Order o ORDER BY o.id ASC";
Queryquery = session.createQuery(hql);
List<Order>orders = query.list();
for(Order o : orders) {
System.out.println(o.getOrderNum());
}*/
分页查询:
query.setFirstResult(int firstResult): 设定从哪一个对象开始检索, 参数 firstResult 表示这个对象在查询结果中的索引位置, 索引位置的起始值为 0. 默认情况下, Query 从查询结果中的第一个对象开始检索。
query.setMaxResult(int maxResults): 设定一次最多检索出的对象的数目.
//分页查询
Stringhql = "FROM Order o ORDER BY o.id ASC";
Queryquery = session.createQuery(hql);
//设置从第几条开始查询,索引从0开始
query.setFirstResult(2);
//设置每次查询几条数据
query.setMaxResults(2);
List<Order>orders = query.list();
for(Order o : orders) {
System.out.println(o.getOrderNum());
}
在映射文件中配置HQL语句:
<!-- name:hql语句的名字,在java代码中要使用 -->
<query name="findCustomerByName">
<![CDATA[FROM Customer cWHERE c.name = ?]]>
</query>
--------------------------
//通过*.hbm.xml配置hql语句,<query>要放在<class>外
Queryquery = session.getNamedQuery("findCustomerByName");
//为占位符?赋值
query.setString(0,"张三");
List<Customer>customers = query.list();
for (Customer c :customers) {
System.out.println(c.getName());
}
模糊查询 like %xx%:
//模糊查询
Stringhql = "FROM Customer c where c.name like ?"; //占位符中不用写通配符
Queryquery = session.createQuery(hql);
query.setString(0,"%张%"); //给占位符设置值时要写通配符
List<Customer>customers = query.list();
for (Customer c :customers) {
System.out.println(c.getName());
}
连接查询:
//连接查询
Stringhql = "FROM Customer c LEFT OUTER JOIN c.orderSet o WHEREc.name = ?";
Queryquery = session.createQuery(hql);
query.setString(0,"张三");
/*
* List的元素为Object数组objects
* objects的元素为Object数组os
* os的元素为客户或订单
*/
List<Object[]> objects = query.list();
for (Object[] os :objects) {
for (Object o : os) {
if(o instanceof Customer) {
Customerc = (Customer) o;
System.out.println(c.getName());
}elseif(o instanceof Order) {
Orderorder = (Order) o;
System.out.println(order.getOrderNum());
}
}
}
投影查询:
查询结果仅包含实体的部分属性.通过 SELECT 关键字实现
//投影查询
Stringhql = "SELECT c.name FROM Customer c"; //只查询名字
Queryquery = session.createQuery(hql);
List<Object>objects = query.list();
for (Object os :objects) {
System.out.println(os);
}
报表查询:
报表查询用于对数据分组和统计,与 SQL 一样, HQL 利用 GROUP BY 关键字对数据分组, 用 HAVING 关键字对分组数据设定约束条件.
在 HQL 查询语句中可以调用以下聚集函数:
count()
min()
max()
sum()
avg()
SELECT count(c) FROM Customer c
SELECT sum(c.id),avg(c.id) FROM Customer c
SELECT min(c.id),max(c.id) FROM Customer c
FROM Order o GROUP BY o.customer
子查询:
select o.orderNum from Order o whereo.customer.id = (select c.id from Customer c where c.name=?)
2.Hibernate的检索策略
立即检索: 立即加载检索方法指定的对象
延迟检索: 延迟加载检索方法指定的对象
2.1类级别:(建议lazy=false,即立即检索)
session.get(xx,xx)方法:返回真实对象或null
1.无论*.hbm.xml中<class>的属性lazy=”true”(默认值)还是lazy=”false”,都是立即检索,即当get方法一执行完就查询数据库。
session.load(xx,xx)方法:返回的对象一定是非空的(代理对象或真实对象)
1.当*.hbm.xml中<class>的属性lazy=”true” (默认值)时,延迟检索,返回的是代理对象,对象是要真正返回对象的子类。获取id属性值时是不会产生sql的(即不会查询数据库)。执行commit方法提交时也不会。获取非id属性值时才会产生sql,即查询数据库(如果数据库没有对应的记录会发生对象找不到异常)。
2.当*.hbm.xml中<class>的属性lazy=”false” (默认值)时,立即检索, 执行玩load方法就查询数据库了,返回真正的对象,而不是代理对象。
2.2关联级别(有集合存在): (建议lazy=true,即延迟检索)
session.get(xx,xx)方法:只要set的lazy属性为false就立即检索
<class lazy="true"/> +<set lazy="true"/>
<class lazy="false"/> +<set lazy="true"/>
在需要取得所有订单时,才临时查询所有订单。
<class lazy="true"/> +<set lazy="false"/>
<class lazy="false"/> +<set lazy="false"/>
在查询客户时,将客户关联的所有订单都查询出来。
session.load(xx,xx)方法:只有class和set的lazy属性同时为false才立即检索
<class lazy="true"/> +<set lazy="true"/>
<class lazy="true"/> +<set lazy="false"/>
<class lazy="false"/> +<set lazy="true"/>
在需要取得所有订单时,才临时查询所有订单。
<class lazy="false"/> +<set lazy="false"/>
在查询客户时,将客户关联的所有订单都查询出来。
get方法和load方法两次加载相同的对象:立即和延迟都是第一次查询,第二次不查询。