级别: 中级
获取本文中所使用的产品以及工具
软件工程师, IBM
2004 年 11 月
如果您是 developerWorks 的订户,就会拥有单用户的使用许可,以使用 WebSphere Application Server 和其他 DB2®, Lotus®, Rational®, Tivoli® 产品,包括基于 Eclipse 的 WebSphere Studio IDE -- 来开发、测试、评估以及演示您的应用程序。如果您不是 developerWorks 的订户,现在可以预定。
前言
Hibernate 是一个流行的开源对象关系映射工具,运行在 Java 环境中。用基于 SQL 的模式可以把数据呈现从对象模型映射到关系数据模型,对象关系映射引用了这项技术。这也就意味着在与数据库交互时,Hibernate 提供了多级抽象方法。
Hibernate 非常灵活,并且支持多种使用方法。在一种情况下,使用 Hibernate API 的最小子集,它仅仅可以用来同数据库交互,在这种情况下,应用程序必须为自己提供连接并且管理自己的事务;例如 WebSphere Application Server 这样的中间件可以实现这些功能。在另一种情况下,即使您没有运行中间件,您也可以使用完整版本的 Hibernate,在这种情况下,您向 Hibernate 提供数据库配置信息,这时它不仅仅为您创建和管理连接,而且还可以通过把事务委派到底层数据库来管理它们。
使用 Hibernate,您需要创建 Java 类来描述数据库中的表,并且将类中的实例变量映射到数据库中的列。这时,正如您所想的那样,您可以调用 Hibernate 的方法来选择、插入、更新和删除底层表中的记录,而不是自己创建和执行查询。
Hibernate 架构有三个主要的组件:
Hibernate 非常的灵活,并且提供多种途径来使用这些组件:
当涉及到对象关系映射时,Hibernate 是非常好的工具,但是在连接管理以及事务管理方面,它却缺乏必要的性能和能力。幸运的是,我们可以将 Hibernate 的对象关系映射与 WebSphere Application Server 的连接和事务管理结合起来,创建强大的应用程序。
本文假设您已经具备了 Hibernate、Enterprise JavaBean(EJB)组件以及 Struts 的基础知识。如果您刚刚接触 Hibernate,请参考没有对象的对象关系映射,这篇文章讨论了怎么用 Hibernate 来实现简单的插入、更新以及删除操作。
关于示例应用程序
为了实现本文的目的,我们将创建一个简单的 Struts Web 应用程序,它允许用户来向 Contact 表中插入新的记录。我们的示例应用程序将使用 AddContact.jsp
来接收用户的输入。AddContactAction.java
是活动类,它将用 Hibernate 来插入一个新的联系人到数据库中去。如果联系人成功插入,这时用户被重定向到 suclearcase/" target="_blank" >ccess.jsp
,这个页面将显示最新插入联系人的详细信息。如果遇到了问题,将显示 failure.jsp
页面。
使用 Hibernate
开始时,我们将创建实例应用程序,这个程序使用 Hibernate 自己的连接池以及事务管理(同样请参考 "full cream" 架构):
struts-blank.war
来实现。为示例应用程序创建必须的 JSP 页面和活动类,您也可以从下载文件 sample1.zip
中导入。
hibernate2.jar
以及 JAR 库文件(dom4j.jar,xmlapi.jar
及其他),到 WEB-INF/lib
目录中。
Contact.java
类,并且为 Contact 中的每一列创建一个成员变量。每个字段都应该创建 Getter 和 Setter 方法。同样需要创建 contact.hbm.xml
文件,这个文件将把 Contact.java
的实例变量映射到 Contact 表的列上。
hibernate.cfg.xml
。这个文件为 Hibernate 保存应用程序级别的配置信息,正如清单 1 所示的那样。
清单 1
|
hibernate.connection.driver_class
是我们决定要使用的 JDBC 驱动器类。
hibernate.connection.password
和 hibernate.connection.username
是数据库的信任状。
hibernate.connection.url
是用来连接数据库的 JDBC URL。dialect
属性决定了在获取查询的时候用到的专用语。Hibernate 支持所有流行的关系数据库管理系统(RDBMS)的专用语,例如 DB2 或者 Oracle™。因此,例如,如果您在开发过程中使用 Oracle,并且在生产的时候想要转移到 DB2 上,仅仅需要改变 hibernate.cfg.xml
文件。
hibernate.hbm2ddl.auto
可以用来指示 Hibernate,当我们初始化它时,从映射文件为我们的应用程序创建 DDL,并且在数据库中创建这些表和序列。create-drop
的值意味着当 Hibernate 关闭时将删除由 Hibernate 创建的表。
contact.hbm.xml
是 Contact 标的映射文件。如果您有多个表,您即可以创建多个映射文件(每个表一个),以及添加多个 <mapping>
元素,也可以在一个文件中创建多个映射,并且添加一个 <mapping>
元素。AddContactAction.java
类执行这个方法:
清单 2
|
new Configuration().configure().buildSessionFactory()
来初始化 Hibernate。Hibernate 会设法在根目录中定位 /hibernate.cfg.xml
,如果发现的话就会加载它,并且提供给我们一个到 SessionFactory 的引用,我们可以用它来同 Hibernate 交互。会话(session)指示了一个逻辑上的交互;在一个会话中您可以激活多个查询。
Contact
类的新实例。通过调用 setter 方法来用输入的联系人信息设定各个字段的值,这时把这个联系人对象传递给 Hibernate,调用 session.save() 来保存。Hibernate 将负责生成和执行插入查询。当联系人被插入时,Contact
类中 ID 字段的值将和 Contact 表中最新插入的记录主键值相同。如果出现任何问题,Hibernate 将会抛出异常。请您确认复制 JDBC 驱动器 JAR 文件到 WEB-INF/lib
目录中,否则将出现异常。
为了尝试这个示例,请下载 sample1.zip 文件。
通过 WebSphere Application Server 连接池来使用 Hibernate
基于上面我们已经完成的内容,我们可以改进示例联系人管理应用程序,它包含 WebSphere Application Server 一些关键特性的使用。
首先,在开发上面的应用程序时,我们用了 Hibernate 中的连接池。这个连接池算法有点不成熟,并且并不能用在生产环境里面,您应该考虑使用第三方的连接池比如 Apache's DBCP。我们将更改我们的应用程序,来使用 WebSphere Application Server 的连接池:
jdbc/ds1
。(参考 WebSphere Application Servers Information Center 来查看配置数据源的细节。)在 hibernate.cfg.xml
文件中,移除 hibernate.connection.driver_class
、URL 以及其他属性,并且添加这一行:
<property name="hibernate.connection.datasource">jdbc/ds1</property>
AddContactAction.java
执行方法中,我们每次都创建一个 SessionFactory 对象,但这并不是一个好主意,因为使用 SessionFactory 创建由所有应用程序线程共享的线程安全对象是非常昂贵的。我们应该仅仅在应用程序启动的时候创建 SessionFactory 对象。我们可以创建一个 SessionContextListener 类并且通过配置 SessionFactory 来实现它,也可以通过更好的办法,创建一个配置 SessionFactory 的 Struts 插件来实现,如清单 3 所示。
清单 3
|
HibernateStrutsPlugin
类。在这个类的 init() 方法中,调用 Configuration().configure().buildSessionFactory()
方法。
struts-config.xml
中为新的插件类添加条目,既可以通过使用 Application Developer(图 2)来实现,也可以通过手动编辑 struts-config.xml
并且在末端添加清单 4 中的那一行。
图 2. Struts Configuration File Editor
清单 4
|
hibernate.cfg.xml
文件做一些修改,使重新使用 SessionFactory 更加得容易。通过添加下面的条目,我们告诉 Hibernate 当我们调用 Configuration().configure()
时,它应该创建 SessionFactory 的一个实例,并且将它同 HibernateSessionFactory 绑定在一起。当把 SessionFactory 绑定到 JNDI 时,Hibernate 将在初始化 InitialContext 时使用 hibernate.jndi.url
以及 hibernate.jndi.class
的值。如果这些值没有指定,将使用默认的 InitialContext 值。
<property name="hibernate.session_factory_name"> HibernateSessionFactory</property>
AddContact.jsp
来添加这两个新的输入。我们想要应用程序完成的功能是,如果用户指定了电话号码或者是地址,一条新的记录将添加到合适的表中。另外,所有这些都应该是一个事务的一部分,也就是说,在添加联系人和电话号码以后,在添加地址是突然出现了错误,这时所有与该事务关联活动都应该回滚,并且将向用户显示出错页面。
创建 Address.java
和 Phone.java
来描述 Address 以及 Phone 表,并且通过 address.hbm.xml
和 contact.hbm.xml
来映射。在 hibernate.cfg.xml
中为这两个文件添加 <mapping>
元素。
清单 5
|
由于这些改变,我们已经:
如果所有的东西都运行正常,我们将在关闭会话以前提交事务。如果出现了任何问题,我们将调用事务对象中的 rollback() 方法。
利用 WebSphere Application Server 事务管理来使用 Hibernate
第二,现在我们想要更改我们的应用程序,使非 Web 客户端也可以访问。为了实现这个目标,我们将创建一个无状态会话 Bean,并且对外公开一个 addContact() 方法,并且,把所有的业务逻辑从 AddContactAction
类中移动到 ContactBean.java
中。
因为移动到无状态会话 Bean 的缘故,我们必须初始化 Hibernate 的方法。对于绑定对象来说,JNDI 一旦可用,就应该初始化 Hibernate,并且应该把 SessionFactory 对象绑定到 JNDI。当应用程序服务器已经完成了启动以后,WebSphere Application Server 就会允许我们注册回滚通知。
HibernateJNDIListener.java
,如清单 6 所示。
清单 6
|
HibernateJNDIListener
)的类,这个类实现了 CustomService 接口。
当应用程序服务器或者节点启动时,这个类也将启动,并且 initialize() 方法中获取控制权,该方法将注册一个 HibernateJNDIListner
实例用来接收 TYPE_J2EE_STATE_RUNNING 通知。HibernateJNDIListner
类实现了 NotificationListener 来指明它现在已经可以接收通知。当绑定对象可以使用 WebSphere Application Server 中的 JNDI 时,它将调用 HibernateJNDIListener
中的 Notification() 处理方法。在这个方法中,我们将初始化 SessionFactory 并且将其在 JNDI 中绑定。
.hbm.xml
文件需要与 sampleListener.jar
在同一个级别上。创建一个新的 Java 项目,sampleDB,并且将 com.sample.db
Java 文件移动到这个项目中,.hbm.xml
和 hibernate.cfg.xml
文件也是一样处理。
sampleDB.jar
和 sampleListener.jar
复制到 appserver\lib
中,以下文件也一样处理:
hibernate2.jar
do dom4j.jar
cgilib-full-2.0.1.jar
xml-apis.jar
commons-collection-2.1.jar
ecache-0.7.jar
.systemout.log
,找到表明 Hibernate 配置成功的消息。
hibernate.cfg.xml
中添加这个条目,来与 WebSphere Application Server 事务管理结合在一起。
<property name="net.sf.hibernate.transaction.JTATransactionFactory"> net.sf.hibernate.transaction.WebSphereTransactionManagerLookup</property>
在这个例子中,我们不会手动指定事务的边界。WebSphere Application Server 在它调用 addContact() 方法时将开始一个新的事务。如果该方法正常完成了执行操作,没有抛出任何错误,这时事务将被提交,否则将回滚。
结束语
当使用 Hibernate 的时候,如果您没有应用服务器,就应该使用完整的架构;例如,您有一个要与数据库交互的 SWING 应用程序。在这种情况下 Hibernate 可以节省您很多低级别的消耗。然而,如果您运行了中间件,您可以使用 WebSphere Application Server 中配置的数据源,因为它为性能做了优化,并且您可以在部属的多个应用程序中共享同样的连接池。
对于企业应用程序,您可能有数据库、消息系统以及各种 EIS 系统,并且您想所有需要的系统都可以运行在一个事务中。在这种情况下,您应该在 Hibernate 中使用 WebSphere Application Server 提供的 Java Transaction API(JTA);当 Hibernate 管理事务时,它通过把调用委托给底层数据库来实现这一点,但是当它是跨系统而不是数据库时,将会出现问题。
Name | Size | Download method | |||||||||
sample1.zip | 5.0 MB | FTP|HTTP | |||||||||
sample2.zip | 5.0 MB | FTP|HTTP | |||||||||
sample3.zip | 5.6 MB | FTP|HTTP | |||||||||
关于作者 Sunil Patil 是一个在 IBM 印度公司 Lotus 部门的一位软件工程师。他具有四年的 J2EE 经验。 |