一.
序
在实际项目中使用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的