Hibernate

Hibernate in action 中文翻译 page 41-48
第一、二个选项除了快速测试和原型外很少使用,大多数应用需要一个固定的配置文件。文件hibernate.properties和hibernate.cfg.xml提供了配置Hibernate的相同的功能。选择使用哪个文件依赖于你的语法爱好。像你将要在本章中看到的一样,也可能混合使用这两种选择并且对开发和配置使用不同的设置。

一种罕见的使用选择是允许应用从会话工厂中打开一个Hibernate会话时提供JDBC连接(例如通过调用sessions.openSession(myConnection))。使用这种选择意味着你不必指定任何数据库连接属性。对新的应用我们不推荐这种方法,因为它们可以使用环境中的数据库连接的底层构造(例如,JDBC连接池或者应用服务器数据源)进行配置。

在所有的配置选项中,数据库连接的设置是最重要的。它们在管理与非管理环境中的设置是不同的,因此我们独立地处理这两种情况。让我们首先从非管理环境开始。

2.3.2 在非管理环境中配置

在非管理环境例如Servlet容器中,应用负责取得JDBC连接。Hibernate是应用的一部分,因此,它会负责取得这些连接。但需要你告诉Hibernate如何取得(或创建)JDBC连接。通常,每次与数据库交互都创建一个连接的做法是不可取的。相反,Java应用应该使用JDBC连接池。这有三方面的原因:

■ 获得新连接的代价是很昂贵的。
■ 维护许多无用的连接也是很浪费的。
■ 对许多驱动程序来说创建预编译语句同样是很昂贵的。

图2.2显示了JDBC连接池在Web应用运行环境中的角色。因为非管理环境没有实现连接池,所以应用必须实现自己的池化算法或者依赖于第三方类库例如开源的C3P0连接池。不使用Hibernate时,应用代码通常直接调用连接池来获得JDBC连接并执行SQL语句。

 
(图2.2)

使用Hibernate时,图像发生了改变:它被作为JDBC连接池的一个客户,如图2.3所示。应用代码使用Hibernate会话和查询API进行持续性操作并且理论上只需要使用Hibernate事务API管理数据库事务。

 
(图2.3)

使用连接池
Hibernate定义了一个插件体系结构,允许你与任何连接池集成。然而,Hibernate内置了对C3P0的支持,因此我们将使用它。Hibernate使用特定的属性为你建立连接池。一个使用了C3P0的hibernate.properties文件的例子参见清单2.4。

hibernate.connection.driver_class = org.postgresql.Driver
hibernate.connection.url = jdbc:postgresql://localhost/auctiondb
hibernate.connection.username = auctionuser
hibernate.connection.password = secret
hibernate.dialect = net.sf.hibernate.dialect.PostgreSQLDialect
hibernate.c3p0.min_size = 5
hibernate.c3p0.max_size = 20
hibernate.c3p0.timeout = 300
hibernate.c3p0.max_statements = 50
hibernate.c3p0.idle_test_period = 3000
(清单2.4)

从第一行开始,以上代码分别指定了下面这些信息:
■ 实现JDBC驱动程序的Java类的名称(驱动程序的jar文件必须位于应用的classpath中)。
■ 指定JDBC连接的主机名和数据库名的JDBC URL。
■ 数据库用户名。
■ 指定用户的数据库密码。
■ 一种数据库方言。尽管有ANSI标准化的努力,不同的数据库厂商还是有不同的SQL实现。因此,你必须指定一种方言。Hibernate对所有流行的SQL数据库都包含内建的支持,并且也很容易定义新的方言。
■ C3P0保持的JDBC连接的最小值。
■ 池中连接的最大值。如果在运行时这个值被耗尽则会抛出一个异常。
■ 一个超时时间(在本例中,是5分钟或300秒),在这之后空闲的连接会被从池中删除。
■ 可以被缓存的预编译语句的最大数量。对预编译语句进行缓存是高性能使用Hibernate必需的。
■ 连接自动生效前的空闲时间(以秒为单位)。

以hibernate.c3p0.*格式指定的属性选择了C3P0作为Hibernate的连接池(为了能支持C3P0,你不需要再设置任何其它选项)。C3P0有比我们在前面的例子中展示的更多的特征,因此我们建议你查询Hibernate API文档。类net.sf.hibernate.cfg.Environment的Javadoc文档化了Hibernate的每一个配置属性,包括所有C3P0相关的设置和其它Hibernate直接支持的第三方连接池的设置。

其它支持的连接池是Apache DBCP和Proxool。在你决定之前,你应该首先在你的环境里试一下每一个连接池。Hibernate社团更倾向于C3P0和Proxool。

Hibernate也包含了一个缺省的连接池机制。这个连接池只适用于测试或试验Hibernate。在产品系统中,你不应该使用这个内建的池。在并发请求较多的环境中它的设计是不可扩展的,并且它缺乏一些专业的连接池才具有的容错性特征。

起动Hibernate
如何使用这些属性起动Hibernate?你在一个名为hibernate.properties的文件中声明这些属性,因此你只需要将这个文件放在应用的classpath中即可。当你创建了一个配置对象,Hibernate首次进行初始化时,它会被自动地检测和读取。

让我们总结一下目前为止你已经学到的配置步骤(如果你想在非配置环境下继续的话,这是下载和安装Hibernate的一个很好的时机)。

1.下载并解包你的数据库的JDBC驱动程序,这通常可以从数据库厂商的Web站点得到。将JAR文件放到应用的classpath中;同时也将hibernate2.jar放在相同的位置。

2.将Hibernate的依赖包放到classpath中;它们在lib/目录中与Hibernate一起发布。同时也要看一下lib/目录下的文本文件README.txt,它包含一个必需与可选库的列表。

3.选择一个Hibernate支持的JDBC连接池并使用属性文件进行配置。不要忘记指定SQL方言。

4.通过将它们放在一个位于classpath中的hibernate.properties文件中,让配置对象知道这些属性。

5.在你的应用中创建一个配置对象的实例并使用addResource()或addClass()方法装载XML映射文件。通过调用配置对象的buildSessionFactory()方法创建一个会话工厂。

很不幸,你还没有任何映射文件。如果你喜欢,你可以运行“Hello World”的例子或者跳过本章剩余的部分并开始学习第3章持续类与映射。或者,如果你想知道更多关于在管理环境中使用Hibernate的知识,请继续往下读。

2.3.3 在管理环境中配置

管理环境处理特定的“cross-cutting”关系,例如应用安全(授权与验证),连接池和事务管理。J2EE应用服务器是典型的管理环境。虽然应用服务器通常是为了支持EJB而设计的,但即使你不使用EJB实体Bean,你仍然可以利用它提供的其它服务。

Hibernate经常与会话或消息驱动EJB一起使用,如图2.4所示。像servlet、JSP和独立的应用一样,EJB调用相同的Hibernate API:Session(会话)、Transaction(事务)和Query(查询)。与Hibernate相关的代码在非管理与管理环境之间是完全可移植的。Hibernate透明地处理了不同的连接与事务策略。

 
(图2.4)

应用服务器将连接池对外显示为JNDI绑定数据源,它是javax.jdbc.Datasource类的一个实例。你需要提供一个JNDI全限定名来告诉Hibernate,到哪里去查找JNDI数据源。这种情况下的一个Hibernate配置文件的例子参见清单2.5。

hibernate.connection.datasource = java:/comp/env/jdbc/AuctionDB
hibernate.transaction.factory_class = net.sf.hibernate.transaction.JTATransactionFactory
hibernate.transaction.manager_lookup_class = net.sf.hibernate.transaction.JBossTransactionManagerLookup
hibernate.dialect = net.sf.hibernate.dialect.PostgreSQLDialect
(清单2.5)

这个文件首先给出了数据源的JNDI名。数据源必须在J2EE企业应用的配置描述符中进行配置;这是一个厂商特定的设置。接着,你允许Hibernate与JTA集成。为了与容器事务完全集成, Hibernate需要定位应用服务器的事务管理器。J2EE规范没有定义标准的方法,但是Hibernate包含了对所有流行的应用服务器的支持。当然,最后还需要指定SQL方言。

现在你已经正确地配置了每件事情,在管理环境中使用Hibernate与在非管理环境中没有太多的区别:都只是使用映射创建一个配置对象并构造一个会话工厂。然而,许多与事物环境有关的设置值得进行额外的考虑。

Java早有了一个标准的事务API:JTA,它用来在J2EE管理环境中控制事务。这被称作容器管理的事务(CMT)。如果存在JTA事务管理器,JDBC连接将被它支持并完全在它的控制之下。这与非管理环境不同,在非管理环境中应用(或连接池)直接管理JDBC连接和JDBC事务。

因此,管理环境与非管理环境可以使用不同的事务方法。因为Hibernate需要在这两种环境之间保证可移植性,因此它定义了一组控制事务的API。Hibernate的事务接口抽象了下层的JTA或JDBC事务(或者,甚至潜在的CORBA事务)。这个下层的事务策略可以使用属性hibernate. connection.factory_class来设置,它可以取下列两值之一:

■ net.sf.hibernate.transaction.JDBCTransactionFactory代表了直接的JDBC事务。这种策略应该与非管理环境中的连接池一起使用,并且如果没有指定任何策略时它就是缺省值。
■ net.sf.hibernate.transaction.JTATransactionFactory代表了JTA。对于CMT这是正确的策略,此时连接由JTA支持。注意如果调用beginTransaction()时已经有一个JTA事务在运行,随后的工作将发生在那个事务的上下文中(否则,将会开始一个新的JTA事务)。

对Hibernate事务API更详细的介绍与它对特定应用场景的影响,请参考第5章第5.1节“事务”。你只要记住使用J2EE服务器工作时必需的两个步骤:像以前描述的那样为Hibernate事务API设置工厂类以支持JTA,并且声明你的应用服务器特定的事务管理器的查找策略。只有你使用了Hibernate的二级缓存系统时查找策略才是必需的,但即使你没有使用缓存设上它也没有坏处。

Hibernate与Tomcat Tomcat并不是一个完整的应用服务器;它只是一个Servlet容器,尽管它包含一些通常只有在应用服务器中才能找到的特征。其中的一个特征可能被Hibernate使用:Tomcat的连接池。Tomcat内部使用的是DBCP连接池,但也像真正的应用服务器一样将它作为JNDI数据源对外显示。为了配置Tomcat数据源,你需要根据Tomcat JNDI/JDBC文档的指导编辑server.xml文件。你可以设置hibernate.connection.datasource来配置Hibernate使用这个数据源。注意Tomcat并不包含一个事务管理器,因此这种情形更像以前描述的非管理环境。

无论使用的是一个简单的Servlet容器还是一个应用服务器,现在你应该有了一个正在运行的Hibernate系统。创建并编译一个持续类(例如,最初的Message类),将Hibernate和它需要的类库以及文件hibernate.properties拷贝到classpath中,构造一个会话工厂。

下一节包含高级的Hibernate配置选项。其中许多是被推荐使用的,例如将可执行的SQL语句写入Log以利于调试;或者使用方便的XML配置文件而不是无格式的属性。然而,你可以安全的跳过这一节而直接去读第三章,在你学到更多关于持续类的知识后再回来。

2.4 高级配置设置

当你最终有了一个可以运行的Hibernate应用时,对Hibernate的所有配置参数有一个全面的了解是非常值得的。这些参数允许你优化Hibernate运行时的行为,特别是调整与JDBC的交互(例如,使用JDBC进行批处理更新时)。

现在我们不会让你对这些细节感到厌烦;关于配置选项最好的信息来源当然是Hibernate的参考文档。在上一节里,我们已经向你说明了一些开始时需要知道的选项。

然而,有一个参数我们必须在这里强调一下。无论何时你使用Hibernate开发软件时都会频繁地用到它。将属性hibernate.show_sql设置为true就可以将所有生成的SQL记录到控制台上。你可以使用它来诊断故障,调整性能或者只是看看生成了什么。它有利于你知道ORM层正在做什么——这就是为什么ORM不对开发者隐藏SQL的原因。

到目前为止,我们一直假定你使用hibernate.properties文件或者在程序里使用一个java.util.Properties的实例来指定配置参数。除此之外,还有你可能会喜欢的第三种选择:使用XML配置文件。

2.4.1 使用基于XML的配置

你可以使用一个XML配置文件(如清单2.6所示)来完全地配置一个会话工厂。不像只包含配置参数的文件hibernate.properties,文件hibernate.cfg.xml也可以指定映射文件的位置。许多用户更喜欢以这种方式集中Hibernate的配置,而不是在应用代码中往配置对象里增加参数。

?xml version='1.0'encoding='utf-8'?>
<!DOCTYPE hibernate-configuration                                             ①
PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd";>
<hibernate-configuration>
<session-factory name="java:/hibernate/HibernateFactory">                 ②
<property name="show_sql">true</property>
<property name="connection.datasource">                               ③
java:/comp/env/jdbc/AuctionDB
</property>
<property name="dialect">
net.sf.hibernate.dialect.PostgreSQLDialect
</property>
<property name="transaction.manager_lookup_class">
net.sf.hibernate.transaction.JBossTransactionManagerLookup
</property>
<mapping resource="auction/Item.hbm.xml"/>                             ④
<mapping resource="auction/Category.hbm.xml"/>
<mapping resource="auction/Bid.hbm.xml"/>
</session-factory>
</hibernate-configuration>
(清单2.6)

① 文档类型声明,XML解析器根据它声明的Hibernate配置DTD来验证文档。

② 可选的name属性等价于属性hibernate.session_factory_name,它用于会话工厂的JNDI绑定,将在下一节进行讨论。

③ 可以不使用“hibernate”作为前缀指定的Hibernate属性。属性名与值在其它方面与程序化的配置属性是相同的。

④ 映射文件可以作为应用资源甚至是硬编码的文件名来指定。这里使用的文件来自于我们的在线拍卖应用,我们将在第3章进行介绍。

现在你可以使用下面的语句初始化Hibernate:
SessionFactory sessions = new Configuration()
.configure().buildSessionFactory();

稍等——Hibernate如何知道配置文件位于哪里?

当调用configure()方法时,Hibernate在classpath中查找名为hibernate.cfg.xml的文件。如果你想使用一个不同的文件名或者想让Hibernate在一个子目录中进行查找,你必须将路径传递给configure()方法。

SessionFactory sessions = new Configuration()
.configure("/hibernate-config/auction.cfg.xml")
.buildSessionFactory();

使用XML配置文件的确比属性文件甚至是程序化的属性配置让人感觉更舒适。这种方法主要的好处是可以让类映射文件从应用的源代码中(即使它仅出现在起动时的帮助类中)具体地表示出来。举例来说,你可以对不同的数据库和环境(开发或产品)使用不同的映射文件(和不同的配置选项),并通过程序切换它们。

如果在classpath中同时存在hibernate.properties和hibernate.cfg.xml两个文件,则XML配置文件的设置会重载属性文件。如果你想在属性文件中保持一些基本设置并且在使用XML配置文件的每一个部署中重载它们时这非常有用。

你可能已经注意到了在XML配置文件中同时给会话工厂指定了一个名字。在会话工厂创建之后,Hibernate自动地使用这个名字将它绑定到JNDI。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值