针对J2EE体系,Hibernate有如下几个集成的方面:
容器管理的数据源(Container-managed datasources): Hibernate能使用通过容器管理,并由JNDI提供的JDBC连接. 通常, 特别是当处理多个数据源的分布式事务的时候, 由一个JTA兼容的
TransactionManager
和一个ResourceManager
来处理事务管理(CMT, 容器管理的事务). 当然你可以通过 编程方式来划分事务边界(BMT, Bean管理的事务). 或者为了代码的可移植性,你也也许会想使用可选的 HibernateTransaction
API.
自动JNDI绑定: Hibernate可以在启动后将
SessionFactory
绑定到JNDI.
JTA Session绑定: Hibernate
Session
可以自动绑定到JTA事务作用的范围. 只需简单地从JNDI查找SessionFactory
并获得当前的Session
. 当JTA事务完成时, 让Hibernate来处理Session
的清洗(flush)与关闭. 事务的划分可以是声明式的(CMT),也可以是编程式的(BMT/UserTransaction).
JMX部署: 如果你使用支持JMX应用程序服务器(如, JBoss AS), 那么你可以选择将Hibernate部署成托管MBean. 这将为你省去一行从
Configuration
构建SessionFactory
的启动代码. 容器将启动你的HibernateService
, 并完美地处理好服务间的依赖关系 (在Hibernate启动前,数据源必须是可用的,等等).
如果应用程序服务器抛出"connection containment"异常, 根据你的环境,也许该将配置属性
hibernate.connection.release_mode
设为after_statement
.
在你的架构中,Hibernate的Session
API是独立于任何事务分界系统的.
如果你让Hibernate通过连接池直接使用JDBC, 你需要调用JDBC API来打开和关闭你的事务.
如果你运行在J2EE应用程序服务器中, 你也许想用Bean管理的事务并在需要的时候调用JTA API和UserTransaction
.
为了让你的代码在两种(或其他)环境中可以移植,我们建议使用可选的Hibernate Transaction
API,
它包装并隐藏了底层系统. 你必须通过设置Hibernate配置属性hibernate.transaction.factory_class
来指定
一个Transaction
实例的工厂类.
有三个标准(内建)的选择:
org.hibernate.transaction.JDBCTransactionFactory
委托给数据库(JDBC)事务(默认)
org.hibernate.transaction.JTATransactionFactory
如果在上下文环境中存在运行着的事务(如, EJB会话Bean的方法), 则委托给容器管 理的事务, 否则,将启动一个新的事务,并使用Bean管理的事务.
org.hibernate.transaction.CMTTransactionFactory
委托给容器管理的JTA事务
你也可以定义属于你自己的事务策略 (如, 针对CORBA的事务服务)
Hibernate的一些特性 (比如二级缓存, Contextual Sessions with JTA等等)需要访问在托管环境中的JTA TransactionManager
.
由于J2EE没有标准化一个单一的机制,Hibernate在应用程序服务器中,你必须指定Hibernate如何获得TransactionManager
的引用:
表 3.10. JTA TransactionManagers
Transaction工厂类 | 应用程序服务器 |
---|---|
org.hibernate.transaction.JBossTransactionManagerLookup |
JBoss |
org.hibernate.transaction.WeblogicTransactionManagerLookup |
Weblogic |
org.hibernate.transaction.WebSphereTransactionManagerLookup |
WebSphere |
org.hibernate.transaction.WebSphereExtendedJTATransactionLookup |
WebSphere 6 |
org.hibernate.transaction.OrionTransactionManagerLookup |
Orion |
org.hibernate.transaction.ResinTransactionManagerLookup |
Resin |
org.hibernate.transaction.JOTMTransactionManagerLookup |
JOTM |
org.hibernate.transaction.JOnASTransactionManagerLookup |
JOnAS |
org.hibernate.transaction.JRun4TransactionManagerLookup |
JRun4 |
org.hibernate.transaction.BESTransactionManagerLookup |
Borland ES |
与JNDI绑定的Hibernate的SessionFactory
能简化工厂的查询,简化创建新的Session
.
需要注意的是这与JNDI绑定Datasource
没有关系, 它们只是恰巧用了相同的注册表!
如果你希望将SessionFactory
绑定到一个JNDI的名字空间,
用属性hibernate.session_factory_name
指定一个名字(如, java:hibernate/SessionFactory
).
如果不设置这个属性, SessionFactory
将不会被绑定到JNDI中. (在以只读JNDI为默认实现的环境中,这个设置尤其有用, 如Tomcat.)
在将SessionFactory
绑定至JNDI时, Hibernate将使用hibernate.jndi.url
,
和hibernate.jndi.class
的值来实例化初始环境(initial context).
如果它们没有被指定, 将使用默认的InitialContext
.
在你调用cfg.buildSessionFactory()
后, Hibernate会自动将SessionFactory
注册到JNDI.
这意味这你至少需要在你应用程序的启动代码(或工具类)中完成这个调用, 除非你使用HibernateService
来做JMX部署 (见后面讨论).
假若你使用JNDI SessionFactory
,EJB或者任何其它类都可以从JNDI中找到此SessionFactory
。
我们建议,在受管理的环境中,把SessionFactory
绑定到JNDI,在其它情况下,使用一个static(静态的)
singleton。为了在你的应用程序代码中隐藏这些细节,我们还建议你用一个helper类把实际查找SessionFactory
的代码隐藏起来,比如HibernateUtil.getSessionFactory()
。注意,这个类也就可以方便地启动Hibernate,参见第一章。
在Hibernate中,管理Session
和transaction最好的方法是自动的"当前"Session
管理。请参见第 2.5 节 “上下文相关的(Contextual)Session”一节的讨论。使用"jta"
session上下文,假若在当前JTA事务中还没有HibernateSession
关联,第一次sessionFactory.getCurrentSession()
调用会启动一个Session,并关联到当前的JTA事务。在"jta"
上下文中调用getCurrentSession()
获得的Session
,会被设置为在transaction关闭的时候自动flush(清洗)、在transaction关闭之后自动关闭,每句语句之后主动释放JDBC连接。这就可以根据JTA事务的生命周期来管理与之关联的Session
,用户代码中就可以不再考虑这些管理。你的代码也可以通过UserTransaction
用编程方式使用JTA,或者(我们建议,为了便于移植代码)使用Hibernate的Transaction
API来设置transaction边界。如果你的代码运行在EJB容器中,建议对CMT使用声明式事务声明。
为了将SessionFactory
注册到JNDI中,cfg.buildSessionFactory()
这行代码仍需在某处被执行.
你可在一个static
初始化块(像HibernateUtil
中的那样)中执行它或将Hibernate部署为一个托管的服务.
为了部署在一个支持JMX的应用程序服务器上,Hibernate和
org.hibernate.jmx.HibernateService
一同分发,如Jboss AS。
实际的部署和配置是由应用程序服务器提供者指定的. 这里是JBoss 4.0.x的jboss-service.xml
样例:
<?xml version="1.0"?> <server> <mbean code="org.hibernate.jmx.HibernateService" name="jboss.jca:service=HibernateFactory,name=HibernateFactory"> <!-- 必须的服务 --> <depends>jboss.jca:service=RARDeployer</depends> <depends>jboss.jca:service=LocalTxCM,name=HsqlDS</depends> <!-- 将Hibernate服务绑定到JNDI --> <attribute name="JndiName">java:/hibernate/SessionFactory</attribute> <!-- 数据源设置 --> <attribute name="Datasource">java:HsqlDS</attribute> <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute> <!-- 事务集成 --> <attribute name="TransactionStrategy"> org.hibernate.transaction.JTATransactionFactory</attribute> <attribute name="TransactionManagerLookupStrategy"> org.hibernate.transaction.JBossTransactionManagerLookup</attribute> <attribute name="FlushBeforeCompletionEnabled">true</attribute> <attribute name="AutoCloseSessionEnabled">true</attribute> <!-- 抓取选项 --> <attribute name="MaximumFetchDepth">5</attribute> <!-- 二级缓存 --> <attribute name="SecondLevelCacheEnabled">true</attribute> <attribute name="CacheProviderClass">org.hibernate.cache.EhCacheProvider</attribute> <attribute name="QueryCacheEnabled">true</attribute> <!-- 日志 --> <attribute name="ShowSqlEnabled">true</attribute> <!-- 映射定义文件 --> <attribute name="MapResources">auction/Item.hbm.xml,auction/Category.hbm.xml</attribute> </mbean> </server>
这个文件是部署在META-INF
目录下的, 并会被打包到以.sar
(service archive)为扩展名的JAR文件中.
同时,你需要将Hibernate、它所需要的第三方库、你编译好的持久化类以及你的映射定义文件打包进同一个文档.
你的企业Bean(一般为会话Bean)可能会被打包成它们自己的JAR文件, 但你也许会将EJB JAR文件一同包含进能独立(热)部署的主服务文档.
参考JBoss AS文档以了解更多的JMX服务与EJB部署的信息.