`
xijunhu
  • 浏览: 155888 次
  • 性别: Icon_minigender_1
  • 来自: 无锡
社区版块
存档分类
最新评论

Hibernate 数据检索...

阅读更多

摘自Hibernate 开发指南(夏昕) 数据检索


数据查询与检索是Hibernate中的一个亮点。相对其他ORM实现而言,Hibernate
提供了灵活多样的查询机制。其中包括:
1. Criteria Query
2. Hibernate Query Language (HQL)
3. SQL

Criteria Query

Criteria Query通过面向对象化的设计,将数据查询条件封装为一个对象。简单来讲,Criteria Query可以看作是传统SQL的对象化表示,如:
Criteria criteria = session.createCriteria(TUser.class);
criteria.add(Expression.eq("name","Erica"));
criteria.add(Expression.eq("sex",new Integer(1)));

这里的criteria 实例实际上是SQL “Select * from t_user where name=’Erica’ and sex=1”的封装(我们可以打开Hibernate 的show_sql 选项,
以观察Hibernate在运行期生成的SQL语句)。
Criteria作为一种对象化的查询封装模式,不过由于Hibernate在实现过程中将精力
更加集中在HQL查询语言上,因此Criteria的功能实现还没做到尽善尽美(这点上,OJB的Criteria 实现倒是值得借鉴),因此,在实际开发中,建议还是采用Hibernate 官方推荐的查询封装模式:HQL。

HQL
相对Criteria,HQL提供了更接近传统SQL语句的查询语法,也提供了更全面的特性。最简单的一个例子:
String hql = "from org.hibernate.sample.TUser";
Query query = session.createQuery(hql);
List userList = query.list();

上面的代码将取出TUser的所有对应记录。
如果我们需要取出名为“Erica”的用户的记录,类似SQL,我们可以通过SQL 语句加以限定:
String hql = "from org.hibernate.sample.TUser as user where user.name='Erica'";
Query query = session.createQuery(hql);
List userList = query.list();

其中我们新引入了两个子句“as”和“where”,as子句为类名创建了一个别名,而where子句指定了限定条件。

HQL子句本身大小写无关,但是其中出现的类名和属性名必须注意大小写区分。

数据关联
一对一关联

配置:
Hibernate中的一对一关联由“one-to-one”节点定义。
在我们的权限管理系统示例中,每个用户都从属于一个用户组。如用户“Erica”
从属于“System Admin”组,从用户的角度出发,这就是一个典型的(单向)一对
一关系。
每个用户对应一个组,这在我们的系统中反映为TUser 到 TGroup 的
one-to-one 关系。其中TUser 是主控方,TGroup是被动方。
one-to-one关系定义比较简单,只需在主控方加以定义。这里,我们的目标是
由TUser 对象获取其对应的TGroup 对象。因此TUser 对象是主控方,为了实现一
对一关系,我们在TUser 对象的映射文件TUser.hbm.xml 中加入one-to-one节
点,对TGroup对象进行一对一关联:

一对多关联
一对多关系在系统实现中也很常见。典型的例子就是父亲与孩子的关系。而在我
们现在的这个示例中,每个用户(TUser)都关联到多个地址(TAddress),如一个
用户可能拥有办公室地址、家庭地址等多个地址属性。这样,在系统中,就反应为一个“一对多”关联。
一对多关系分为单向一对多关系和双向一对多关系。
单向一对多关系只需在“一”方进行配置,双向一对多关系需要在关联双方均加
以配置。

双向一对多关系,实际上是“单向一对多关系”与“多对一关系”的组合。也就
是说我们必须在主控方配置单向一对多关系的基础上,在被控方配置多对一关系与其对应。

多对多关联
Hibernate关联关系中相对比较特殊的就是多对多关联,多对多关联与一对一关
联和一对多关联不同,多对多关联需要另外一张映射表用于保存多对多映射信息。
由于多对多关联的性能不佳(由于引入了中间表,一次读取操作需要反复数次查
询),因此在设计中应该避免大量使用。同时,在对多对关系中,应根据情况,采取
延迟加载(Lazy Loading 参见后续章节)机制来避免无谓的性能开销。
在一个权限管理系统中,一个常见的多对多的映射关系就是Group 与Role,以
及Role与Privilege之间的映射。
. Group代表“组”(如“业务主管”);
. Role代表“角色”(如“出纳”、“财务”);
. Privilege 代表某个特定资源的访问权限(如“修改财务报表”,“查询
财务报表”)。


数据访问
PO和VO
PO即 Persistence Object
VO即 Value Object

PO和VO是Hibernate中两个比较关键的概念。首先,何谓VO,很简单,VO就是一个简单的值对象。如:
TUser user = new TUser();
user.setName("Emma");
这里的user就是一个VO。VO只是简单携带了对象的一些属性信息。何谓PO? 即纳入Hibernate管理框架中的VO。看下面两个例子:

TUser user = new TUser();
TUser anotherUser = new TUser();
user.setName("Emma");
anotherUser.setName("Kevin");
//此时user和anotherUser都是VO
Transaction tx = session.beginTransaction();
session.save(user);
//此时的user已经经过Hibernate的处理,成为一个PO
//而anotherUser仍然是个VO
tx.commit();
//事务提交之后,库表中已经插入一条用户”Emma”的记录
//对于anotherUser则无任何操作
Transaction tx = session.beginTransaction();
user.setName("Emma_1"); //PO
anotherUser.setName("Kevin_1");//VO
tx.commit();
//事务提交之后,PO的状态被固化到数据库中
//也就是说数据库中“Emma”的用户记录已经被更新为“Emma_1”
//此时anotherUser仍然是个普通Java对象,它的属性更改不会
//对数据库产生任何影响
另外,通过Hibernate返回的对象也是PO:
//由Hibernate返回的PO
TUser user = (TUser)session.load(TUser.class,new Integer(1));
VO经过Hibernate进行处理,就变成了PO。

VO和PO的主要区别在于:
VO是独立的Java Object。
PO是由Hibernate纳入其实体容器(Entity Map)的对象,它代表了与数
据库中某条记录对应的Hibernate实体,PO的变化在事务提交时将反应到实
际数据库中。

如果一个PO与Session对应的实体容器中分离(如Session关闭后的PO),那么
此时,它又会变成一个VO。

由PO、VO的概念,又引申出一些系统层次设计方面的问题。如在传统的MVC架构中,位于Model层的PO,是否允许被传递到其他层面。由于PO的更新最终将被映射到实际数据库中,如果PO在其他层面(如View层)发生了变动,那么可能会对Model
层造成意想不到的破坏。

因此,一般而言,应该避免直接PO传递到系统中的其他层面,一种解决办法是,通
过一个VO,通过属性复制使其具备与PO相同属性值,并以其为传输媒质(实际上,
这个VO被用作Data Transfer Object,即所谓的DTO),将此VO传递给其他层
面以实现必须的数据传送。



关于unsaved-value
在非显示数据保存时,Hibernate将根据这个值来判断对象是否需要保存。

Inverse和Cascade
Inverse,直译为“反转”。在Hibernate语义中,Inverse指定了关联关系中的
方向。
关联关系中,inverse=”false”的为主动方,由主动方负责维护关联关系。具体可
参见一对多关系中的描述。
而Cascade,译为“级联”,表明对象的级联关系,如TUser的Cascade设为all,
就表明如果发生对user对象的操作,需要对user所关联的对象也进行同样的操作。如对
user对象执行save操作,则必须对user对象相关联的address也执行save操作。
初学者常常混淆inverse和cascade,实际上,这是两个互不相关的概念。Inverse
指的是关联关系的控制方向,而cascade指的是层级之间的连锁操作。


延迟加载(Lazy Loading)
为了避免一些情况下,关联关系所带来的无谓的性能开销。Hibernate引入了延迟加载的概念。
如,示例中user对象在加载的时候,会同时读取其所关联的多个地址(address)对象,对于需要对address进行操作的应用逻辑而言,关联数据的自动加载机制的确非常有效。
但是,如果我们只是想要获得user的性别(sex)属性,而不关心user的地址(address)信息,那么自动加载address的特性就显得多余,并且造成了极大的性能浪费。为了获得user的性别属性,我们可能还要同时从数据库中读取数条无用的地址数据,这导致了大量无谓的系统开销。
延迟加载特性的出现,正是为了解决这个问题。
所谓延迟加载,就是在需要数据的时候,才真正执行数据加载操作。


事务管理

Hibernate 是JDBC 的轻量级封装,本身并不具备事务管理能力。在事务管理层,
Hibernate将其委托给底层的JDBC或者JTA,以实现事务管理和调度功能。
Hibernate的默认事务处理机制基于JDBC Transaction。我们也可以通过配置文
件设定采用JTA作为事务管理实现:

<hibernate-configuration>
<session-factory>
……
<property name="hibernate.transaction.factory_class">
net.sf.hibernate.transaction.JTATransactionFactory
<!--net.sf.hibernate.transaction.JDBCTransactionFactory-->
</property>
……
</session-factory>
</hibernate-configuration>

基于JDBC的事务管理:
将事务管理委托给JDBC 进行处理无疑是最简单的实现方式,Hibernate 对于JDBC
事务的封装也极为简单。
我们来看下面这段代码:
session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
……
tx.commit();
从JDBC层面而言,上面的代码实际上对应着:
Connection dbconn = getConnection();
dbconn.setAutoCommit(false);
……
dbconn.commit();
就是这么简单,Hibernate并没有做更多的事情(实际上也没法做更多的事情),只
是将这样的JDBC代码进行了封装而已。
这里要注意的是,在sessionFactory.openSession()中,hibernate会初始化
数据库连接,与此同时,将其AutoCommit 设为关闭状态(false)。而其后,在
Session.beginTransaction 方法中,Hibernate 会再次确认Connection 的
AutoCommit 属性被设为关闭状态( 为了防止用户代码对session 的
Connection.AutoCommit属性进行修改)。



基于JTA的事务管理:
JTA 提供了跨Session 的事务管理能力。这一点是与JDBC Transaction 最大的
差异。
JDBC事务由Connnection管理,也就是说,事务管理实际上是在JDBC Connection
中实现。事务周期限于Connection的生命周期之类。同样,对于基于JDBC Transaction的Hibernate 事务管理机制而言,事务管理在Session 所依托的JDBC Connection中实现,事务周期限于Session的生命周期。
JTA 事务管理则由 JTA 容器实现,JTA 容器对当前加入事务的众多Connection 进
行调度,实现其事务性要求。JTA的事务周期可横跨多个JDBC Connection生命周期。
同样对于基于JTA事务的Hibernate而言,JTA事务横跨可横跨多个Session。
。。。。
从上图中我们可以看出,JTA 事务是由JTA Container 维护,而参与事务的
Connection无需对事务管理进行干涉。这也就是说,如果采用JTA Transaction,我
们不应该再调用Hibernate的Transaction功能。

public class ClassC{
public void save(){
……
UserTransaction tx = new InitialContext().lookup(“……”);
ClassA.save(user);
ClassB.save(order);
tx.commit();
……
}
}


这时ClassA和B中不能:
Transaction tx = session.beginTransaction();
直接:
session = sessionFactory.openSession();
session.save(user);
session.close();

虽然:
public class ClassC{
public void save(){
……
session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
classA.save(user);
classB.save(order);
tx.commit();
……
}
}
但实际上,这是利用Hibernate来完成启动和提交UserTransaction的功能,但这
样的做法比原本直接通过InitialContext获取UserTransaction 的做法消耗了更多
的资源,得不偿失。

在EJB 中使用JTA Transaction 无疑最为简便,我们只需要将save 方法配置为
JTA事务支持即可,无需显式申明任何事务,下面是一个Session Bean的save方法,
它的事务属性被申明为“Required”,EJB容器将自动维护此方法执行过程中的事务:
/**
* @ejb.interface-method
* view-type="remote"
*
* @ejb.transaction type = "Required"
**/
public void save(){
//EJB环境中,通过部署配置即可实现事务申明,而无需显式调用事务
classA.save(user);
classB.save(log);
}//方法结束时,如果没有异常发生,则事务由EJB容器自动提交。




锁(locking)

Hibernate分页

Session管理

Cache管理



笔者使用过的ORM 实现中,Apache OJB、Oracle TopLink、IBatis
和Jaxor都给笔者留下了深刻映像,是否选择Hibernate作为持久层实现,
需要结合实际情况考虑(在很多情况下,比如对遗留系统的改造项目中、
ibatis可能更加合适)。

http://blog.ccidnet.com/blog-htm-do-showone-uid-60683-type-blog-itemid-180652.html
分享到:
评论

相关推荐

    08.拓薪教育-hibernate4.3的hibernate.cfg.xml基本配置.part2

    高级Hibernate4开发技术:ORM思想,hibernate介绍,hibernate.cfg.xml配置,hbm.xml映射文件详解,主键生成策略使用,PO对象状态及状态的转换分析、一级缓存,Hibernate数据检索技术,Hibernate高级映射技术,...

    08.拓薪教育-hibernate4.3的hibernate.cfg.xml基本配置.part1

    高级Hibernate4开发技术:ORM思想,hibernate介绍,hibernate.cfg.xml配置,hbm.xml映射文件详解,主键生成策略使用,PO对象状态及状态的转换分析、一级缓存,Hibernate数据检索技术,Hibernate高级映射技术,...

    Hibernate数据检索(HQL)笔记

    ### Hibernate数据检索(HQL)知识点详解 #### 一、简介 Hibernate 是一款开源的对象关系映射(ORM)框架,它允许开发人员将 Java 对象映射到数据库表中的记录,从而极大地简化了数据访问层的开发工作。本文档基于...

    hibernate-release-5.3.2.Final

    1. Session接口:作为与数据库交互的主要接口,Session负责保存、更新、删除和检索对象,支持事务管理和并发控制。 2. Criteria API:提供了一种比HQL更面向对象的查询方式,可以动态构建查询条件,避免硬编码SQL...

    官方原版hibernate-3.2.ga.zip

    Hibernate支持延迟加载、级联操作、事务管理、查询语言(HQL)和 Criteria API,以及复杂的数据检索策略。 值得注意的是,虽然3.2.ga版本稳定,但相比更新的版本,它可能缺乏某些功能和性能优化。例如,较新的...

    hibernate-orm.zip

    此外,Criteria和HQL(Hibernate Query Language)查询提供了更加灵活的检索方式。 5. 第二级缓存与查询缓存: Hibernate支持二级缓存,可以显著提升性能,特别是对于读多写少的应用场景。Query缓存则是在特定条件...

    Manning.Java.Persistence.with.Hibernate.Nov.2006.pdf

    这本书深入探讨了如何使用Hibernate来处理Java应用程序中的数据存储和检索问题,使得开发者可以更高效、更灵活地管理数据库。 Hibernate是一个开源的对象关系映射(ORM)框架,它简化了Java应用程序与数据库之间的...

    hibernate-3.2.5.源代码....

    通过XML配置文件(hibernate.cfg.xml)或注解,开发者可以定义实体类与数据库表的对应关系,使得数据操作更便捷。 2. **SessionFactory和Session**:在Hibernate中,SessionFactory是一个线程安全的工厂类,用于...

    Hibernate搜索框架HibernateSearch.zip

    Hibernate Search的作用是对数据库中的数据进行检索的。它是hibernate对著名的全文检索系统Lucene的一个集成方案,作用在于对数据表中某些内容庞大的字段(如声明为text的字段)建立全文索引,这样通过hibernate ...

    Android应用源码Hibernate4Android.zip

    5. Criteria查询和HQL:使用Hibernate提供的查询语言进行数据检索。 6. 数据库初始化:加载初始数据到数据库,可能使用Hibernate的`hibernate.hbm2ddl.auto`属性或自定义脚本。 7. 性能优化:考虑使用二级缓存、...

    优化Hibernate性能的几点建议

    #### 四、使用Iterator代替List进行数据检索 当处理大量的数据时,使用`Iterator`而不是`List`来遍历结果集可以节省大量的内存资源。这是因为`Iterator`在每次调用`next()`方法时只会加载当前的记录,而不会一次性...

    hibernate-3.3.6.ga.jar.zip

    本次我们将深入探讨的主角是`hibernate-3.3.6.ga.jar`,它是Hibernate 3的一个稳定版本,包含了所有必要的API和实现,为开发者提供了强大的数据持久化功能。 `hibernate-3.3.6.ga.jar`是Hibernate 3的库文件,它...

    Hibernate ORM 5.3.7.Final User Guide

    通过这种技术,Hibernate不仅自动化了从Java类到数据库表的映射过程,还提供了数据查询和检索的功能,大大减少了开发者在手动数据处理上所花的时间。Hibernate的设计目标是通过消除手动、手工制作的数据处理,利用...

    Hibernate数据检索(HQL).rar

    本教程重点聚焦于Hibernate的数据检索机制,特别是Hibernate查询语言(HQL),它是Hibernate提供的一个强大的SQL方言,用于在ORM层面上执行数据库查询。 **一、Hibernate概述** Hibernate作为Java中的ORM框架,它...

    hibernate-3.6.8.Final

    在Hibernate 3.6.8.Final中,配置文件通常为`hibernate.cfg.xml`,定义了数据源、实体映射、缓存策略等。初始化时,通过`Configuration`类加载配置,然后创建`SessionFactory`,它是线程安全的,用于创建会话。 四...

    Hibernate备课笔记.pdf

    2. Session:在Hibernate中,Session是与数据库交互的主要接口,它负责保存和检索持久化对象,实现了事务管理和缓存功能。 3. Transaction:事务管理是数据库操作的基础,Hibernate提供了一种便捷的方式来处理事务,...

    J2EE Hibernate-6.ppt

    《J2EE Hibernate-6.ppt》探讨了Hibernate在J2EE环境中的检索策略,主要涉及立即检索策略、延迟检索策略以及迫切左外连接检索策略。 1. **立即检索策略**: 立即检索策略是Hibernate默认的检索方式。在处理一对多...

Global site tag (gtag.js) - Google Analytics