Hibernate实践

一.             
在实际项目中使用Hibernate有两年多了,在两年多的实践过程中既体验到了Hibernate带来的N多好处,同时也碰到不少的问题,特写此篇文章做个总结,记录自己在Hibernate实践中的一些经验,希望对于新使用Hibernate的朋友能有个帮助,避免走过多的弯路。
阅读本文前建议至少拥有Hibernate的一些基本知识,因为本文不会去详细介绍相关的基本知识,最好就是先用Hibernate开发了一个HelloWorld,^_^。
根据自己所经历的项目中使用Hibernate所涉及的范围,本文从开发环境、开发、设计、性能、测试以及推荐的相关书籍方面进行讲述,本篇文档不会讲的非常细致,只是根据自己在实践时的经验提出一些建议,关于细致以及具体的部分请参阅《Hibernate Reference》或推荐的相关书籍章节。
此文档的PDF版本请到此下载:
http://www.blogjava.net/Files/BlueDavy/Hibernate 实践.rar
本文允许转载,但转载时请注明作者以及来源。
作者:BlueDavy
来源:www.blogjava.net/BlueDavy
二.              开发环境
Hibernate 开发环境的搭建非常的简单,不过为了提高基于Hibernate开发的效率,通常都需要使用一些辅助工具,如xdoclet、middlegen等。
尽管Hibernate已经封装提供了很简单的进行持久的方法,但在实际项目的使用中基本还是要提供一些通用的代码,以便在进行持久的相关操作的时候能够更加的方便。
2.1. lib
2.1.1.        Hibernate lib
Hibernate 相关的 lib 自然是开发环境中首要的问题,这部分可以从 Hibernate 的官方网站进行下载,在其官方网站中同时提供了对于 Hibernate 所必须依赖的 lib 以及其他可选 lib 的介绍。
2.2. xdoclet
Hibernate 作为ORM工具,从名字上就能看出它需要一个从O à R 的Mapping的描述,而这个描述就是在使用Hibernate时常见的hbm.xml,在没有工具支持的情况下,需要在编写持久层对象的同时手写这个文件,甚为不便。
在jdk 5.0未推出之前,xdoclet支持的在javadoc中编写注释生成相关配置文件的方式大受欢迎,减少了编写hibernate映射文件的复杂性,手写一个完整的hibernate映射文件出错几率比较的高,再加上手写容易造成编写出来的风格相差很大,因此,基于xdoclet来生成hbm.xml的方式被大量的采用,基于xdoclet来编写能够基于我们在持久层对象上编写的javadoc来生成hbm.xml文件,非常的方便。
2.2.1.        Hibernate template
如果没记错的话,大概在 04 年的时候 javaeye 上有位同仁整理了一个这样的 template 文件, ^_^ ,非常感谢,我一直都在用着,呵呵。
这个文件的方便就是把它导入 eclipse 后,在 javadoc 中我们可以直接写 hibid ,然后按 eclipse 的代码辅助键 (alt+/) 来生成整个 hibernate.id 的相关的格式,呵呵,免得在写 hibernate.id 这些东西的时候过于麻烦, ^_^ ,这个 template 文件我稍微做了修改,可在这里下载:
http://www.blogjava.net/Files/BlueDavy/templates-eclipse-tags.rar
当然,你也可以选择直接用 xdoclet 提供的 template 文件,不过 xdoclet 官方网站上好像只提供了可直接导入 idea 的模板文件。
关于注释上的 hibernate.id 这些东西具体请参见 xdoclet 官方网站的说明。
如果你的项目采用的是 jdk 5 ,那么就可以直接使用 hibernate annotation 了,那就更为方便。
2.2.2.        Ant task build
Eclipse 里没有集成 xdoclet 的插件,你也可以去安装一个 jboss ide 的插件,里面有 xdoclet 的插件,反正我是觉得太麻烦了。
在项目中我仍然采用 ant task 的方式来生成 hbm.xml target 如下所示:
<path id="app.classpath">
<pathelement path="${java.class.path}"/>
<fileset dir="${xdoclib.dir}">
<include name="*.jar"/>
</fileset>
</path>
<target name="hbm" description=" 生成映射文件 ">
<tstamp>
<format property="TODAY" pattern="yy-MM-dd"/>
</tstamp>
<taskdef name="hibernatedoclet" classname="xdoclet.modules.hibernate.HibernateDocletTask" classpathref="app.classpath"/>
<hibernatedoclet destdir="src/java" force="true" verbose="true" excludedtags="@version,@author,@todo">
<fileset dir="src/java">  
<include name="**/po/**/*.java"/>
</fileset>
<hibernate version ="3.0"/>
</hibernatedoclet>
</target>
这个文件请根据项目情况以及环境稍做修改, ^_^ ,其中需要通过 properties 文件指明 xdocletlib.dir ,类似 xdocletlib.dir=c:/xdocletlib ,里面放置 xdoclet 的相关 jar 文件。
在搭建好了这样的环境后,就可以在直接在 eclipse 中运行 ant 文件中的这个 target 来生成 hbm.xml
2.3. Hibernate3 Tools
如果采用Hibernate 3,则可以直接下载Hibernate 3 Tools的Eclipse Plugin,那就可以类似在PL/SQL里执行sql一样在eclipse里执行hql,^_^
2.4. HibernateUtil
为了方便项目中Hibernate的使用,一般来说都会提供HibernateUtil这样的类,这个类的作用主要是创建sessionFactory和管理session,在Hibernate 3以前采用的是在这里建立ThreadLocal来存放session,在Hibernate 3以后则可以直接使用SessionFactory.getCurrentSession来获取session,而session的获取方式则可通过在hibernate.cfg.xml中执行current_session_context_class的属性来决定是采用thread或jta或自定义的方式来产生session。
2.5. CommonDao
在持久层部分目前采用的较多的仍然是dao模式,Hibernate作为ORM工具已经提供了CRUD的封装,类如可以使用session.save();session.persist()这样简单的方式来完成CRUD的操作,但在实际的项目中还是需要提供一个通用的Dao,来简化对于事务、异常处理以及session的操作,同时提供一些项目中需要的相关操作。
三.              开发
在完成了Hibernate的开发环境的搭建后,就可以基于Hibernate进行持久层的开发了,对于持久层开发来说,会涉及到实体的编写、实体的维护以及实体的查询三个部分。
3.1. 实体的编写
Hibernate 的一个明显的优点就是在于可透明化的对对象进行持久,这也就意味着持久对象根本就不需要依赖任何的东西,可以采用POJO的方式来编写,在Hibernate 3以上版本还提供了对于Map、XML的方式的持久的支持,就更方便了,在项目中,更多采用的仍然是POJO的方式。
在实体的编写上应该说不会有什么问题,只要仔细查看xdoclet关于hibernatedoclet部分的说明即可完成。
这块需要学习的主要是普通的值类型注释的编写、id字段注释的编写、关联注释的编写,这些部分xdoclet均提供了较详细的说明。
3.2. 实体的维护
3.2.1.        新增 / 编辑 / 删除
新增 / 编辑 / 删除是持久操作中最常使用的维护性操作,基于 Hibernate 做这样的维护就比采用 sql 的方式简单多了,通过上面 CommonDao ,就可以直接完成 dao.save dao.update dao.delete 的操作,而且在 Hibernate 3 也支持了批量的 insert update delete
这个部分中需要注意的是 Hibernate 对于对象的三种状态的定义:
u       Transient
很容易理解,就是从未与 session 发生过关系的对象, ^_^ ,例如在代码中直接 User user=new User() ;这样形成的 user 对象,就称为 Transient 对象了。
u       Detached
同样很容易理解,就是与 session 发生过关系的对象,但 session 已经关闭了的情况下存在的对象,例如:
User user=new User();
user.setName(“bluedavy”);
session.save(user);
session.close();
session.close() 后这个时候的 user 对象就处于 Detached 状态之中了,如果想将这个对象变为 Persistent 状态,可以通过 session.merge session.saveOrUpdate() 等方式来实现。
Detached 状态的对象在实际的应用中最常采用,从概念上我们可以这么理解,处于 Detached 状态的对象可以看做是一个 DTO ,而不是 PO ,这从很大程度上就方便了 PO 在实际项目中的使用了。
u       Persistent
Persistent 状态就是指和 Session 发生了关系的对象,并且此时 session 未关闭,举例如下:
User user=new User();
user.setName(“bluedavy”);
session.save(user);
user.getName();
session.save user 就处于 Persistent 状态,此时如果通过 session 根据 user id 去获取 user 对象,则可发现获取的对象和之前的 user 是同一个对象,这是 session 一级缓存所起的作用了,当然,也可以强制的刷新 session 的一级缓存,让 session 从数据库中重新获取,只需要在获取前执行 session.evict(user) session.clear()
3.2.2.        关联维护
关联维护在 Hibernate 中表现出来可能会让熟悉使用 sql 的人有些的不熟,但其实以对象的观点去看是会觉得很正常的。
Hibernate 的关联维护中,最重要的是 inverse cascade 两个概念。
u       inverse
inverse 从词义上看过去可能不是那么容易理解,其实它的意思就是由谁来控制关联关系的自动维护,当 inverse=true 就意味着当前对象是不能自动维护关联关系,当 inverse=false 就意味着当前对象可自动维护关联关系,还是举例来说:
假设 Org User 一对多关联,
org getUsers inverse=false 的情况:
org.getUsers().add(user);
dao.save(org);
这样执行后将会看到数据库中 user 这条记录中的 orgId 已经被设置上去了。
inverse=true 的情况下,执行上面的代码,会发现在数据库中 user 这条记录中的 orgId 没有被设置上去。
^_^ inverse 的作用这样可能看的不是很明显,在下面的一对多中会加以描述。
u       cascade
cascade 的概念和数据库的 cascade 概念是基本一致的, cascade 的意思形象的来说就是当当前对象执行某操作的情况下,其关联的对象也执行 cascade 设置的同样的操作。
例如当 org.getUsers cascade 设置为 delete 时,当删除 org 时,相应的 users 也同样被删除了,但这个时候要注意, org.getUsers 这个集合是被删除的 user 的集合,也就是说如果这个时候数据库中新增加了一个 user org ,那么这个 user 是不会被删除的。
cascade 的属性值详细见《 Hibernate reference 》。
3.2.2.1.           一对一
一对一的关联维护在实际项目中使用不多,一对一在Hibernate中可采用两种方式来构成,一种是主键关联,一种是外键关联。
一对一的使用推荐使用主键关联,具体配置方法请参见《Hibernate Reference》。
3.2.2.2.           一对多/多对一
一对多/多对一的关联维护在实际项目中使用是比较多的,在Hibernate中可采用多种方式来配置一对多的关联,如采用Set、List、Bag、Map等,具体在《Hibernate Reference》中都有详细说明。
在这里我想说的一点就是关于inverse的设置,在一对多的情况下建议将一端的inverse设为true,而由多端去自动维护关联关系,为什么这样做其实挺容易理解的,假设org和user为一对多的关联,org.getUsers的inverse设置为false,org.getUsers().add(user);dao.update(org);当update的时候org所关联的所有user的orgId都会更新一次,可想而知这个效率,而如果改为在多端维护(多端设置为inverse=false),则是这样:user.setOrg(org);dao.update(user);当update的时候就仅仅是更新user这一条记录而已。
另外一点就是合理的设置cascade,这个要根据需求来实际决定。
3.2.2.3.           多对多
多对多的关联维护在实际项目中其实也是比较多的,尽管在《Hibernate Reference》中认为多对多的情况其实很多时候都是设计造成的。
多对多的关联也同样可以采用Set、List等多种方式来配置,具体在《Hibernate Reference》中也有详细的说明。
多对多的关联维护上没有什么需要多说的,在实践过程中来看这块不会出什么太多问题,唯一需要注意的是合理设置cascade,这个要根据项目的实际情况而定。
3.3. 实体的查询
Hibernate 提供了多种方式来支持实体的查询,如对于原有熟悉sql的人可以继续使用sql,符合对象语言的对象查询语句(HQL)以及条件查询API(Criteria)。
在熟练使用hql或criteria的情况下,我相信你会觉得Hibernate的查询方式会比采用sql的方式更加简便。
3.3.1.        符合对象语言的查询语句
Hibernate 提供了一种符合对象语言的查询语句,称为 HQL ,这种语句的好处是能够避免使用 sql 的情况下依赖数据库特征的情况出现,同时它带来的最大的好处就是我们能够根据 OO 的习惯去进行实体的查询。
对于 HQL 没有什么多讲的,如果熟悉 sql 的人应该也是能够很快就学会 HQL ,而如果不熟悉 sql 的人那也没关系, HQL 的上手是非常容易的,具体请参考《 Hibernate Reference 》。
3.3.2.        占位符式的查询
占位符式的查询 ( 就是采用 ? 替换查询语句中的变量 ) 是在采用 sql 的情况下经常使用的一种查询方式,也是查询时推荐使用的一种方式。
Hibernate 中的查询参数主要有两种类型:值类型和实体类型,值类型就是指一个切实的值 ( String int List 这些 ) ,实体类型就是一个具体的实体,如编写的 User Organization 等,值类型的查询和普通 sql 几乎一样,而实体类型的查询就体现了 Hibernate 的强项, ^_^ ,可以起到简化 sql 的作用,并且使得查询语句更加容易理解。
3.3.2.1.           值类型
3.3.2.1.1.      简单值
举例如下:
from User u where u.name=:username and u.yearold=:yearold
这就是一个常见的简单值的占位符式的查询,通过这样的方式就可以把值注入到参数中:
query.setParameter(“username”,”bluedavy”);
query.setParameter(“yearold”,25);
同样, hibernate 也支持和 sql 完全相同的 ? 的方式,那么上面的语句以及注入参数的方式就变为了:
from User u where u.name=? and u.yearold=?
query.setParameter(0,”bluedavy”);
query.setParameter(1,25);
推荐使用第一种,那样参数的意义更容易被理解。
3.3.2.1.2.      in 查询
in 查询也是经常被使用到的一种查询,在 Hibernate 中表现出来会稍有不同,不过如果按照对象观点去看就很容易理解了,例如下面这句:
from User u where u.name in (:usernameList)
Hibernate 中通过这样的方式将值注入到这个参数中:
List list=new ArrayList();
list.add(“jerry”);
list.add(“bluedavy”);
query.setParameterList(“usernameList”,list);
sql 中通常是组装一个由 , 连接的值来构成 in 中的参数值,而在 Hibernate 中则依照对象转化为采用 list 了, ^_^ ,是不是更方便些。
3.3.2.2.           实体类型
在Hibernate中关联采用的都是对象形式,表现对外就是隐藏了数据库的外键的部分,这也就对习惯使用sql查询的人带来一个问题,因为无法再操作外键字段,那么在涉及到关联的实体的查询时应该怎么做呢,我把它分为单实体和实体集合两种情况来说说。
3.3.2.2.1.      单实体
单实体的查询对应到 sql 情况通常是在一对多的情况下通过多端查询同时结合一端的一些过滤条件,在 sql 中通常采用 join 的方式来实现这个,而在 Hibernate 中要实现这点就更容易了,举例如下:
User Organization 是一对多,现在要查询属于组织机构名称为 ”Blogjava” 以及用户年龄大于 20 的用户:
from User u where u.org.name=:orgname and u.yearold>:yearold
query.setParameter(“orgname”,”Blogjava”);
query.setParameter(“yearold”,20);
可以看到这样的查询语句比 sql 更简单多了,同时也更容易理解多了。
3.3.2.2.2.      实体集合
实体集合过滤形式的查询在实际的项目中也经常会碰到,仍然用上面的例子,但改为通过 Organization 去查询:
from Organization org where org.name=:orgname and org.users.yearold>:yearold
是不是比 sql 简单多了,而且更容易理解呢, ^_^
这个时候对象化查询语句的优势就体现出来了,而不用陷入 sql 的那种关系型的通过外键进行查询的方式。
3.3.3.        NamedQuery
NamedQuery 的意思就是指在 PO 的映射文件中定义关于 PO 的查询语句,而在应用中指需要直接调用此查询语句的别名即可,这个好处非常明显,使得所有的查询语句可以统一的进行管理,同样,我们可以在 PO 中通过 javadoc 的方式进行定义,这就更方便了, ^_^
操作 NamedQuery 的方法和普通 hql 的方法基本一样:
session.getNamedQuery(queryname);
其中的 queryname 就是我们定义的查询语句的别名,一个 namedQuery 的语句的示例如下:
< query name = "validate" ><![CDATA[
from User u where u.loginname=:loginname and u.password=:password
]]></ query >
3.3.4.        Criteria
条件查询的 API 使得我们可以采用完全对象化的方式进行实体的查询,而不是通过 hql 的方式,在实际项目中,使用 hql 的方式更为居多,毕竟写起来更方便。
关于 Criteria 的具体介绍请参阅《 Hibernate Reference 》。
3.3.5.        原生 SQL
原生 SQL 不推荐使用,但在某些确实需要用 sql 的情况下那么 Hibernate 还是支持的,具体见《 Hibernate Reference 》。
四.              设计
独立的编写这个章节的原因是希望在采用Hibernate的情况下充分的去发挥Hibernate的优势,改变我们以关系形式去做持久层的设计的惯性思维,形成以OO的思想去设计持久层,所以我非常推荐通过写PO去生成数据表的方式,而不是设计表反向导成PO的形式,当然,对于原有的系统那就没办法了。
OO 思想中的核心三要素:封装、继承和多态,在Hibernate的支持下同样可以充分发挥OO的三要素来优化持久层的设计。
4.1. 封装
4.1.1.        Component
Hibernate 中有一个 Component 的概念,这就允许在进行持久层设计的时候采用细粒度级的领域模型进行设计,例如在 User 对象中需要记录 User firstname lastname 这些信息,而在其他的表中也有这种需求,那么在 Hibernate 中我们就可以把 firstname lastname 组装为一个 UserName 对象,作为 Component 放入 User 中,在 user 中就可以变为采用 user.getUserName.getFristName 的方式来获取。
Component 对于我们采用对象的封装概念进行持久层设计提供了很好的支持,同时在 Hibernate 中还有 Elements Properties 这些元素,具体请参见《 Hibernate Reference 》。
4.2. 继承
继承使得我们可以对持久层中的对象进行抽象,类如我们可以形成Person这个对象,而User、Employee都继承自这个对象。
继承在数据库形式的设计中固然也可以实现,但通常不能以对象的观点去发挥的淋漓尽致,当然不是说以对象的方式去设计一定是最好的。
在Hibernate中对于继承映射到数据表有几种不同的策略,各有适用的不同场合,具体的解释和说明见《Hibernate Reference》
4.2.1.        单表策略
单表策略很容易理解,就是将类、子类中所有的属性都放至一张表中,这对于子类属性不多的情况非常有效。
Hibernate 中通常将子类定义为 @hibernate.subclass 的方式来实现这个策略。
4.2.2.        每个子类一张表
每个子类一张表在 Hibernate 中有几种实现方式, @hibernate.join-subclass @hibernate.join-subclass-key 的组合方式以及 @hibernate.join-subclass @hibernate.discriminator 的组合方式是较常用的两种方式,第一种方式采用的是主键关联方式,第二种方式采用的是 discriminator 字段的关联方式,个人比较推崇第一种方式。
这种策略适合在子类属性和父类有较大不同的情况下采用。
4.2.3.        每个具体类一张表
这种策略适合在类层次结构上有一定数量的抽象类的情况下使用,同样有两种方式,一种是采用显式多态的方式,另一种是采用隐式多态的方式,显式多态采用的为 @hibernate.union-subclass 的方式,隐式多态则采用每个具体类的 PO 独立建表的策略,在它的映射文件中将看不出任何的和接口、抽象类的关系,同时对于抽象类,需要指明其 abstract=”true”
4.3. 多态
4.3.1.        查询
在查询中很容易体现 Hibernate 对于多态的支持,如系统有 Person 对象、 User Employee 分别继承自 Person ,同时 Person Organization 对象关联,这个时候我们通过 Organization 获取其关联的 Person 时得到的既有可能是 User ,也有可能是 Employee ^_^…
五.              性能
Hibernate 作为ORM工具,从性能上来讲带给了很多人忧虑,但我觉得Hibernate在性能上也许会带来少许的降低,但如果对于不能合理设计数据库和使用SQL的人来说,我觉得Hibernate反倒能提高性能,除非是在一些特殊的场合,如报表式的那种查询推荐继续采用JDBC的方式。
Hibernate 在性能提升上其实有很多种做法,在《Hibernate Reference》中也有专门的提升性能的章节,在这里我提几点在项目中通常采用的方法。
5.1. Lazy Load
Lazy Load 是常用的一种提升性能的方法,这个其实很容易理解,在不采用lazy load的情况下,Hibernate在获取一个PO的时候,将同时获取PO中的属性、PO中的集合以及集合中对象的属性、集合,这样看过去很容易看出,如果对象的关联结构有深层次的话,最后搞不好整个库都被加载出来了,而在实际使用中往往可能只需要用到PO中的一两个属性而已,这点也是之前的ORM产品经常被批的一点,就是ORM产品不能象sql那样只获取需要的东西,^_^,其实Hibernate在这点上一直就支持,而且支持的还不错,在Hibernate 3以后,默认的lazy就已经设置为true了,这个时候包括po中的属性都是采用lazy load的方式,只有在调用到这个属性时才会从缓存或数据库中加载,当然,集合也同样如此。
在lazy load上推荐不要什么字段都采用lazy load的方式,对于一些基本属性的字段建议将其lazy设置为false,而对于一些可能需要消耗内存的字段,如clob这样的字段对象的lazy设置为true,对于集合则全部设置为lazy=true。
是否采用Lazy load对系统的性能会有非常明显的影响,同时尽量不要将Detached Object放入Http的session中。
5.1.1.        OSIV
OSIV Open Session In View ,在 B/S 系统中通常采用这种方式来更好的去支持 Lazy load ,意思就是在 View 加载前打开 Session ,在 View 加载完毕后关闭 Session 的方式,在 Spring 中有 OpenSessionInViewFilter ,可参考或直接使用。
5.2. Cache
Cache 是在提升系统性能方面常用的方法,在Hibernate中通常有非常好的对于Cache的支持方法,Hibernate中对于Cache有一级缓存和二级缓存的概念,一级缓存是必须的,位于Session部分,二级缓存则不是必须的,由开发人员自行指定,二级缓存可指定使用何种开源的cache工具,Hibernate 3以后的版本默认使用的是Ehcache,也可以切换为Oscache、JbossCache,对我而言最重要的区别在于对于cluster的支持上。
二级缓存能够明显的提高系统的性能,当然,同时也会更加的消耗内存,可以通过配置文件来指定内存中能够加载的最多的元素,这有利于避免消耗过多内存。
二级缓存的设置在Hibernate中非常的简单,只需要在相应的hbm.xml中增加cache元素,指明使用何种策略,如read-only、read-write等,也可以直接在hibernate.cfg.xml中增加class-cache的方式来进行全局指定。
5.3. 高效的查询语句
查询语句的是否高效对于系统的性能也是会造成明显的影响的,为了方便系统性能的调优,建议大家对查询语句进行统一管理,如统一采用NamedQuery的方式,在这样的情况下可以在系统运行时请教数据库专家,由他们来分析系统中的查询语句的执行效率以及提出改进策略,而对于开发人员来讲,在查询语句方面最能够注意的就是采用占位符式的查询。
5.3.1.        占位符式的查询
数据库对于所有的 sql 语句都要进行语法分析,而其分析通常会受到语句中的大小写、空格以及参数不同的影响,在其语法分析器认为不同的情况下将再次进行分析,这就不可避免的降低了响应的速度,而采用占位符式的查询则可保证语法分析器只进行一次的分析,在参数不同的情况并不会出现重复解析的现象,其次就是要统一查询语句的编写风格,包括大小写、空格这些。
我不是很确定 Hibernate 中对于语句的语法分析,估计和数据库的这种方式应该差不多,不过猜想可能会更智能一些, ^_^
5.4. 一些配置
hibernate.cfg.xml 中的一些配置也会对性能产生一定的影响,如 jdbc.fetch_size 的设置等,还有象采用连接池方面的设置,对于 B/S 应用的情况建议尽量采用应用服务器提供的 JNDI 的方式。
5.5. 建议
在性能提升方面从两方面入手,一是持久层对象的设计上,这方面可以参考《 Hibernate Reference 》中提升性能章节中的一些建议,另一方面则是请教数据库专家,由数据库专家对表结构、查询语句等进行分析来给出改进策略,在现有的一个项目中,竟然有出现 Hibernate 在外键上没建立索引的现象出现?
六.              测试
6.1. 编写专门的测试用的配置文件
测试方面也是极度关心的话题,在测试方面其实比较简单,只需要在测试类中采用专门用于测试的配置文件即可,在这个配置文件中,通过都是采用设置hbm2ddl.auto属性为create-drop的方式,也就是在测试类运行前创建表,在测试类运行后删除表的策略,在更多的情况下,我们可以采用in-memory的数据库的方式,如hsql,当然,有些时候则需要和实际运行环境一致,那么就需要采用建立专门的测试库的方式,避免测试数据和运行数据的相互影响。
七.              企业应用开发
事务和并发是企业应用开发中非常关注的两个话题,在《Hibernate Reference》中提供了详细的方案,在这里我就简单的说说。
7.1. 事务
事务是企业应用开发中非常重视的一点,而在Hibernate中操作此部分和sql方式没有什么很大的区别,可以通过session主动去获取Transaction来实现事务控制,同时也可以交由应用服务器提供的JTA来实现事务控制。
在事务这个级别上如果有更高的要求,建议采用Spring的事务框架。
7.2. 并发
在并发方面多采用锁策略,锁策略和数据库基本相同,同样是乐观锁和悲观锁两种策略,乐观锁策略在Hibernate中推荐使用version或timestamp来实现,具体覆盖方式则需要根据应用而定,如是采用最新的修改的覆盖还是采用版本冲突策略等,悲观锁策略则通过指定对象的锁方式,如LockMode.READ,引用《Hibernate Reference》中的一段话:
“用户其实并不需要花很多精力去担心锁定策略的问题。通常情况下,只要为JDBC连接指定一下隔离级别,然后让数据库去搞定一切就够了。然而,高级用户有时候希望进行一个排它的悲观锁定,或者在一个新的事务启动的时候,重新进行锁定。Hibernate总是使用数据库的锁定机制,从不在内存中锁定对象!
如果数据库不支持用户设置的锁定模式,Hibernate将使用适当的替代模式,这一点可以确保应用程序的可移植性。”。
用户可通过几种方式来指定锁定模式:
u       Session.load() 的时候指定锁定模式LockMode;
u       Session.lock()
u       Query.setLockMode()
八.              相关书籍
Hibernate 上手并不难,但要真正的用好它确实不是件容易的事,有些书籍能够很好的帮我们快速的提供解决思路和解决方案,而这些书籍我们也应该常备,以方便自己在有些问题上的解答。
同时,我一直坚持的观点,一种开源框架通常带来的不仅仅是开发、使用上的改变,带来的最大的改变仍然是在设计层次上的,设计上能否充分的发挥开源框架的优势才是最为重要的。
8.1. 《Hibernate Reference》
这本没什么说的,必读书籍,也许在读的时候很多东西你不会觉得什么,但当碰到一些确定方向的问题时,可以通过此书快速的查找到相应的解决方案,感谢Redsaga组织的翻译工作,使得我们可以有中文版可看。
目前版本(Hibernate 3.1.2)的下载地址:
8.2. 《Hibernate in action》
In action 系列的书籍也没啥多说的,强烈推荐看看,尽管现在看起来版本有些老了,但里面很多的实践思想仍然是非常值得学习的,网上应该有很多电子版下载的地方。
8.3. 《深入浅出Hibernate》
这本书想必大家也听闻了不少,简称白皮书,^_^,是夏昕、曹晓刚以及唐勇三位大师的大作。
 
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第一部分 从Hibernate和EJB 3.0开始  第1章 理解对象/关系持久化    1.1 什么是持久化     1.1.1 关系数据库     1.1.2 理解SQL     1.1.3 在Java中使用SQL     1.1.4 面向对象应用程序中的持久化    1.2 范式不匹配     1.2.1 粒度问题     1.2.2 子类型问题     1.2.3 同一性问题     1.2.4 与关联相关的问题     1.2.5 数据导航的问题     1.2.6 不匹配的代价    1.3 持久层和其他层 显示全部信息第一部分 从Hibernate和EJB 3.0开始  第1章 理解对象/关系持久化    1.1 什么是持久化     1.1.1 关系数据库     1.1.2 理解SQL     1.1.3 在Java中使用SQL     1.1.4 面向对象应用程序中的持久化    1.2 范式不匹配     1.2.1 粒度问题     1.2.2 子类型问题     1.2.3 同一性问题     1.2.4 与关联相关的问题     1.2.5 数据导航的问题     1.2.6 不匹配的代价    1.3 持久层和其他层     1.3.1 分层架构     1.3.2 用SQL/JDBC手工编写持久层     1.3.3 使用序列化     1.3.4 面向对象的数据库系统     1.3.5 其他选项    1.4 ORM     1.4.1 什么是ORM     1.4.2 一般的ORM问题     1.4.3 为什么选择ORM     1.4.4 Hibernate、EJB 3和JPA简介    1.5 小结   第2章 启动项目    2.1 启动Hibernate项目     2.1.1 选择开发过程     2.1.2 建立项目     2.1.3 Hibernate配置和启动     2.1.4 运行和测试应用程序    2.2 启动Java Persistence项目     2.2.1 使用Hibernate Annotations     2.2.2 使用Hibernate EntityManager     2.2.3 引入EJB组件     2.2.4 切换到Hibernate接口    2.3 反向工程遗留数据库     2.3.1 创建数据库配置     2.3.2 定制反向工程     2.3.3 生成Java源代码    2.4 与Java EE服务整合     2.4.1 与JTA整合     2.4.2 JNDI绑定的SessionFactory     2.4.3 JMX服务部署    2.5 小结   第3章 领域模型和元数据    3.1 CaveatEmptor应用程序     3.1.1 分析业务领域     3.1.2 CaveatEmptor领域模型    3.2 实现领域模型     3.2.1 处理关注点渗漏     3.2.2 透明和自动持久化     3.2.3 编写POJO和持久化实体类     3.2.4 实现POJO关联     3.2.5 把逻辑添加到访问方法    3.3 ORM元数据     3.3.1 XML中的元数据     3.3.2 基于注解的元数据     3.3.3 使用XDoclet     3.3.4 处理全局的元数据     3.3.5 运行时操作元数据    3.4 其他实体表示法     3.4.1 创建动态的应用程序     3.4.2 表示XML中的数据    3.5 小结  第二部分 映射概念和策略  第4章 映射持久化类    4.1 理解实体和值类型     4.1.1 细粒度的领域模型     4.1.2 定义概念     4.1.3 识别实体和值类型    4.2 映射带有同一性的实体     4.2.1 理解Java同一性和等同性     4.2.2 处理数据库同一性     4.2.3 数据库主键    4.3 类映射选项     4.3.1 动态的SQL生成     4.3.2 使实体不可变     4.3.3 给查询命名实体     4.3.4 声明包名称     4.3.5 用引号把SQL标识符括起来     4.3.6 实现命名约定    4.4 细粒度的模型和映射     4.4.1 映射基础属性     4.4.2 映射组件    4.5 小结   第5章 继承和定制类型    5.1 映射类继承     5.1.1 每个带有隐式多态的具体类一张表     5.1.2 每个带有联合的具体类一张表     5.1.3 每个类层次结构一张表     5.1.4 每个子类一张表     5.1.5 混合继承策略     5.1.6 选择策略    5.2 Hibernate类型系统     5.2.1 概述实体和值类型     5.2.2 内建的映射类型     5.2.3 使用映射类型    5.3 创建定制的映射类型     5.3.1 考虑定制的映射类型     5.3.2 扩展点     5.3.3 定制映射类型的案例     5.3.4 创建UserType     5.3.5 创建CompositeUserType     5.3.6 参数化定制类型     5.3.7 映射枚举    5.4 小结   第6章 映射集合和实体关联    6.1 值类型的set、bag、list和map     6.1.1 选择集合接口     6.1.2 映射set     6.1.3 映射标识符bag     6.1.4 映射list     6.1.5 映射map     6.1.6 排序集合和有序集合  6.2 组件的集合     6.2.1 编写组件类     6.2.2 映射集合     6.2.3 启用双向导航     6.2.4 避免非空列    6.3 用注解映射集合     6.3.1 基本的集合映射     6.3.2 排序集合和有序集合     6.3.3 映射嵌入式对象的集合    6.4 映射父/子关系     6.4.1 多样性     6.4.2 最简单的可能关联     6.4.3 使关联双向     6.4.4 级联对象状态    6.5 小结   第7章 高级实体关联映射    7.1 单值的实体关联     7.1.1 共享的主键关联     7.1.2 一对一的外键关联     7.1.3 用联结表映射    7.2 多值的实体关联     7.2.1 一对多关联     7.2.2 多对多关联     7.2.3 把列添加到联结表     7.2.4 映射map    7.3 多态关联     7.3.1 多态的多对一关联     7.3.2 多态集合     7.3.3 对联合的多态关联     7.3.4 每个具体类一张多态表    7.4 小结   第8章 遗留数据库和定制SQL    8.1 整合遗留数据库     8.1.1 处理主键     8.1.2 带有公式的任意联结条件     8.1.3 联结任意的表     8.1.4 使用触发器    8.2 定制SQL     8.2.1 编写定制CRUD语句     8.2.2 整合存储过程和函数    8.3 改进Schema DDL     8.3.1 定制SQL名称和数据类型     8.3.2 确保数据一致性     8.3.3 添加领域约束和列约束     8.3.4 表级约束     8.3.5 数据库约束     8.3.6 创建索引     8.3.7 添加辅助的DDL    8.4 小结  第三部分 会话对象处理  第9章 使用对象    9.1 持久化生命周期     9.1.1 对象状态     9.1.2 持久化上下文    9.2 对象同一性和等同性     9.2.1 引入对话     9.2.2 对象同一性的范围     9.2.3 脱管对象的同一性     9.2.4 扩展持久化上下文    9.3 Hibernate接口     9.3.1 保存和加载对象     9.3.2 使用脱管对象     9.3.3 管理持久化上下文    9.4 JPA     9.4.1 保存和加载对象     9.4.2 使用脱管的实体实例    9.5 在EJB组件中使用Java Persistence     9.5.1 注入EntityManager     9.5.2 查找EntityManager     9.5.3 访问EntityManagerFactory    9.6 小结   第10章 事务和并发    10.1 事务本质     10.1.1 数据库和系统事务     10.1.2 Hibernate应用程序中的事务     10.1.3 使用Java Persistence的事务    10.2 控制并发访问     10.2.1 理解数据库级并发     10.2.2 乐观并发控制     10.2.3 获得额外的隔离性保证    10.3 非事务数据访问     10.3.1 揭开自动提交的神秘面纱     10.3.2 使用Hibernate非事务地工作     10.3.3 使用JTA的可选事务    10.4 小结   第11章 实现对话    11.1 传播Hibernate Session     11.1.1 Session传播的用例     11.1.2 通过线程局部传播     11.1.3 利用JTA传播     11.1.4 利用EJB传播    11.2 利用Hibernate的对话     11.2.1 提供对话保证     11.2.2 利用脱管对象的对话     11.2.3 给对话扩展Session    11.3 使用JPA的对话     11.3.1 Java SE中的持久化上下文传播     11.3.2 在对话中合并脱管对象     11.3.3 在Java SE中扩展持久化上下文    11.4 使用EJB 3.0的对话     11.4.1 使用EJB的上下文传播     11.4.2 利用EJB扩展持久化上下文    11.5 小结   第12章 有效修改对象    12.1 传播性持久化     12.1.1 按可到达性持久化     12.1.2 把级联应用到关联     12.1.3 使用传播性状态     12.1.4 利用JPA的传播性关联    12.2 大批量和批量操作     12.2.1 使用HQL和JPA QL的大批量语句     12.2.2 利用批量处理     12.2.3 使用无状态的会话    12.3 数据过滤和拦截     12.3.1 动态数据过滤     12.3.2 拦截Hibernate事件     12.3.3 内核事件系统     12.3.4 实体监听器和回调    12.4 小结   第13章 优化抓取和高速缓存    13.1 定义全局抓取计划     13.1.1 对象获取选项     13.1.2 延迟的默认抓取计划     13.1.3 理解代理     13.1.4 禁用代理生成     13.1.5 关联和集合的即时加载     13.1.6 通过拦截延迟加载    13.2 选择抓取策略     13.2.1 批量预抓取数据     13.2.2 通过子查询预抓取集合     13.2.3 通过联结即时抓取     13.2.4 给二级表优化抓取     13.2.5 优化指导方针    13.3 高速缓存基本原理     13.3.1 高速缓存策略和范围     13.3.2 Hibernate高速缓存架构    13.4 高速缓存实践     13.4.1 选择并发控制策略     13.4.2 理解高速缓存区域     13.4.3 设置本地的高速缓存提供程序     13.4.4 设置重复的高速缓存     13.4.5 控制二级高速缓存    13.5 小结   第14章 利用HQL和JPA QL查询    14.1 创建和运行查询     14.1.1 准备查询     14.1.2 执行查询     14.1.3 使用具名查询    14.2 基本的HQL和JPA QL查询     14.2.1 选择     14.2.2 限制     14.2.3 投影    14.3 联结、报表查询和子查询     14.3.1 联结关系和关联     14.3.2 报表查询     14.3.3 利用子查询    14.4 小结   第15章 高级查询选项    15.1 利用条件和示例查询     15.1.1 基本的条件查询     15.1.2 联结和动态抓取     15.1.3 投影和报表查询     15.1.4 按示例查询    15.2 利用原生的SQL查询     15.2.1 自动的结果集处理     15.2.2 获取标量值     15.2.3 Java Persistence中的原生SQL    15.3 过滤集合    15.4 高速缓存查询结果     15.4.1 启用查询结果高速缓存     15.4.2 理解查询高速缓存     15.4.3 什么时候使用查询高速缓存     15.4.4 自然标识符高速缓存查找    15.5 小结   第16章 创建和测试分层的应用程序    16.1 Web应用程序中的Hibernate     16.1.1 用例简介     16.1.2 编写控制器     16.1.3 OSIV模式     16.1.4 设计巧妙的领域模型    16.2 创建持久层     16.2.1 泛型的数据访问对象模式     16.2.2 实现泛型CRUD接口     16.2.3 实现实体DAO     16.2.4 利用数据访问对象    16.3 命令模式简介     16.3.1 基础接口     16.3.2 执行命令对象     16.3.3 命令模式的变形    16.4 利用EJB 3.0设计应用程序     16.4.1 利用有状态的bean实现会话     16.4.2 利用EJB编写DAO     16.4.3 利用依赖注入    16.5 测试     16.5.1 理解不同种类的测试     16.5.2 TestNG简介     16.5.3 测试持久层     16.5.4 考虑性能基准    16.6 小结   第17章 JBoss Seam简介    17.1 Java EE 5.0编程模型     17.1.1 JSF详解     17.1.2 EJB 3.0详解     17.1.3 用JSF和EJB 3.0编写Web应用程序     17.1.4 分析应用程序    17.2 用Seam改善应用程序     17.2.1 配置Seam     17.2.2 将页面绑定到有状态的Seam组件     17.2.3 分析Seam应用程序    17.3 理解上下文组件     17.3.1 编写登录页面     17.3.2 创建组件     17.3.3 给上下文变量起别名     17.3.4 完成登录/注销特性    17.4 验证用户输入     17.4.1 Hibernate Validator简介     17.4.2 创建注册页面     17.4.3 用Seam实现国际化    17.5 利用Seam简化持久化     17.5.1 实现对话     17.5.2 让Seam管理持久化上下文    17.6 小结  附录A SQL基础知识  附录B 映射快速参考

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值