针对J2EE体系,Hibernate有如下几个集成的方面:
容器管理的数据源(Container-managed datasources): Hibernate能使用通过容器管理,并由JNDI提供的JDBC连接. 通常, 特别是当处理多个数据源的分布式事务的时候, 由一个JTA兼容的TransactionManager
和一个 ResourceManager
来处理事务管理(CMT, 容器管理的事务). 当然你可以通过 编程方式来划分事务边界(BMT, Bean管理的事务). 或者为了代码的可移植性,你也也许会想使用可选的 Hibernate Transaction
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,参见第一章。
The easiest way to handle Session
s and transactions is Hibernates automatic "current" Session
management. See the discussion of current sessions. Using the "jta"
session context, if there is no Hibernate Session
associated with the current JTA transaction, one will be started and associated with that JTA transaction the first time
you call sessionFactory.getCurrentSession()
. The Session
s retrieved via getCurrentSession()
in "jta"
context will be set to automatically flush before the transaction completes, close after the transaction completes, and aggressively
release JDBC connections after each statement. This allows the Session
s to be managed by the life cycle of the JTA transaction to which it is associated, keeping user code clean of such management
concerns. Your code can either use JTA programmatically through UserTransaction
, or (recommended for portable code) use the Hibernate Transaction
API to set transaction boundaries. If you run in an EJB container, declarative transaction demarcation with CMT is preferred.
为了将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"> <!-- Required services --> <depends>jboss.jca:service=RARDeployer</depends> <depends>jboss.jca:service=LocalTxCM,name=HsqlDS</depends> <!-- Bind the Hibernate service to JNDI --> <attribute name="JndiName">java:/hibernate/SessionFactory</attribute> <!-- Datasource settings --> <attribute name="Datasource">java:HsqlDS</attribute> <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute> <!-- Transaction integration --> <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> <!-- Fetching options --> <attribute name="MaximumFetchDepth">5</attribute> <!-- Second-level caching --> <attribute name="SecondLevelCacheEnabled">true</attribute> <attribute name="CacheProviderClass">org.hibernate.cache.EhCacheProvider</attribute> <attribute name="QueryCacheEnabled">true</attribute> <!-- Logging --> <attribute name="ShowSqlEnabled">true</attribute> <!-- Mapping files --> <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部署的信息.