【转】Hibernate 配置

时间:2022-06-14 07:24:48

转自:http://www.blogjava.net/19851985lili/articles/108128.html

由于Hibernate是为了能在各种不同环境下工作而设计的, 因此存在着大量的配置参数. 幸运的是多数配置参数都 有比较直观的默认值, 并有随Hibernate一同分发的配置样例hibernate.properties (位于etc/)来展示各种配置选项. 所需做的仅仅是将这个样例文件复制到类路径 (classpath)下做一些自定义的修改.

4.1. 可编程的配置方式

一个org.hibernate.cfg.Configuration实例代表了一个应用程序中Java类型 到SQL数据库映射的完整集合. Configuration被用来构建一个(不可变的 (immutable))SessionFactory. 映射定义则由不同的XML映射定义文件编译而来.

你可以直接实例化Configuration来获取一个实例,并为它指定XML映射定义 文件. 如果映射定 义文件在类路径(classpath)中, 请使用addResource():

Configuration cfg = new Configuration()
.addResource("Item.hbm.xml")
.addResource("Bid.hbm.xml");
一个替代方法(有时是更好的选择)是,指定被映射的类,让Hibernate帮你寻找映射定义文件:

Configuration cfg = new Configuration()
.addClass(org.hibernate.auction.Item.class)
.addClass(org.hibernate.auction.Bid.class);
Hibernate将会在类路径(classpath)中寻找名字为 /org/hibernate/auction/Item.hbm.xml和 /org/hibernate/auction/Bid.hbm.xml映射定义文件. 这种方式消除了任何对文件名的硬编码(hardcoded).

Configuration也允许你指定配置属性:

Configuration cfg = new Configuration()
.addClass(org.hibernate.auction.Item.class)
.addClass(org.hibernate.auction.Bid.class)
.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect")
.setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test")
.setProperty("hibernate.order_updates", "true");
当然这不是唯一的传递Hibernate配置属性的方式, 其他可选方式还包括:

传一个java.util.Properties实例给 Configuration.setProperties().

将hibernate.properties放置在类路径(classpath)的根目录下 (root directory).

通过java -Dproperty=value来设置系统 (System)属性.

在hibernate.cfg.xml中加入元素 <property> (稍后讨论).

如果想尽快体验Hbernate, hibernate.properties是最简单的方式.

Configuration实例是一个启动期间(startup-time)的对象, 一旦SessionFactory创建完成它就被丢弃了.

4.2. 获得SessionFactory

当所有映射定义被Configuration解析后, 应用程序必须获得一个用于构造Session实例的工厂. 这个工厂将被应用程序的所有线程共享:

SessionFactory sessions = cfg.buildSessionFactory();
Hibernate允许你的应用程序创建多个SessionFactory实例. 这对 使用多个数据库的应用来说很有用.

4.3. JDBC连接

通常你希望SessionFactory来为你创建和缓存(pool)JDBC连接. 如果你采用这种方式, 只需要如下例所示那样,打开一个Session:

Session session = sessions.openSession(); // open a new Session
一旦你需要进行数据访问时, 就会从连接池(connection pool)获得一个JDBC连接.

为了使这种方式工作起来, 我们需要向Hibernate传递一些JDBC连接的属性. 所有Hibernate属性的名字和语义都在org.hibernate.cfg.Environment中定义. 我们现在将描述JDBC连接配置中最重要的设置.

如果你设置如下属性,Hibernate将使用java.sql.DriverManager来获得(和缓存)JDBC连接 :

表 4.1. Hibernate JDBC属性

Hibernate JDBC属性
属性名 用途
hibernate.connection.driver_class jdbc驱动类
hibernate.connection.url jdbc URL
hibernate.connection.username 数据库用户
hibernate.connection.password 数据库用户密码
hibernate.connection.pool_size 连接池容量上限数目

但Hibernate自带的连接池算法相当不成熟. 它只是为了让你快些上手,不适合用于产品系统或性能测试中。 出于最佳性能和稳定性考虑你应该使用第三方的连接池。只需要连接池的特定设置替换 hibernate.connection.pool_size。这将关闭Hibernate自带的连接池. 例如, 你可能会想用C3P0.

C3P0是一个随Hibernate一同分发的开源的JDBC连接池, 它位于lib目录下。 如果你设置了hibernate.c3p0.*相关的属性, Hibernate将使用 C3P0ConnectionProvider来缓存JDBC连接. 如果你更原意使用Proxool, 请参考发 行包中的hibernate.properties并到Hibernate网站获取更多的信息.

这是一个使用C3P0的hibernate.properties样例文件:

hibernate.connection.driver_class = org.postgresql.Driver
hibernate.connection.url = jdbc:postgresql://localhost/mydatabase
hibernate.connection.username = myuser
hibernate.connection.password = secret
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.timeout=1800
hibernate.c3p0.max_statements=50
hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

为了能在应用程序服务器(application server)中使用Hibernate, 你应当总是将Hibernate 配置成注册在JNDI中的Datasource处获得连接,你至少需要设置下列属性中的一个:

表 4.2. Hibernate数据源属性

Hibernate数据源属性
属性名 用途
hibernate.connection.datasource 数据源JNDI名字
hibernate.jndi.url  JNDI提供者的URL (可选)
hibernate.jndi.class JNDI InitialContextFactory类 (可选)
hibernate.connection.username 数据库用户 (可选)
hibernate.connection.password 数据库用户密码 (可选)

这里有一个使用应用程序服务器JNDI数据源的hibernate.properties样例文件:

hibernate.connection.datasource = java:/comp/env/jdbc/test
hibernate.transaction.factory_class = \
org.hibernate.transaction.JTATransactionFactory
hibernate.transaction.manager_lookup_class = \
org.hibernate.transaction.JBossTransactionManagerLookup
hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

从JNDI数据源获得的JDBC连接将自动参与应用程序服务器中容器管理的事务(container-managed transactions)中去.

任何连接(connection)配置属性的属性名要以"hibernate.connnection"前缀开头. 例如, 你可能会使用hibernate.connection.charSet来指定charSet.

通过实现org.hibernate.connection.ConnectionProvider接口,你可以定义属于 你自己的获得JDBC连接的插件策略。通过设置hibernate.connection.provider_class, 你可以选择一个自定义的实现.

4.4. 可选的配置属性

有大量属性能用来控制Hibernate在运行期的行为. 它们都是可选的, 并拥有适当的默认值.

警告: 其中一些属性是"系统级(system-level)的". 系统级属性可以通过java -Dproperty=value或 hibernate.properties来设置, 而不能用上面描述的其他方法来设置.

表 4.3. Hibernate配置属性

Hibernate配置属性
属性名 用途
hibernate.dialect 一个Hibernate Dialect类名允许Hibernate针对特定的关系数据库生成优化的SQL.
取值 full.classname.of.Dialect
hibernate.show_sql 输出所有SQL语句到控制台.
取值 true | false
hibernate.default_schema 在生成的SQL中, 将给定的schema/tablespace附加于非全限定名的表名上.
取值 SCHEMA_NAME
hibernate.default_catalog 在生成的SQL中, 将给定的catalog附加于没全限定名的表名上.
取值 CATALOG_NAME
hibernate.session_factory_name SessionFactory创建后,将自动使用这个名字绑定到JNDI中.
取值 jndi/composite/name
hibernate.max_fetch_depth 为单向关联(一对一, 多对一)的外连接抓取(outer join fetch)树设置最大深度. 值为0意味着将关闭默认的外连接抓取.
取值 建议在0到3之间取值
hibernate.default_batch_fetch_size 为Hibernate关联的批量抓取设置默认数量.
取值 建议的取值为4, 8, 和16
hibernate.default_entity_mode 为由这个SessionFactory打开的所有Session指定默认的实体表现模式.
取值 dynamic-map, dom4j, pojo
hibernate.order_updates 强制Hibernate按照被更新数据的主键,为SQL更新排序。这么做将减少在高并发系统中事务的死锁。
取值 true | false
hibernate.generate_statistics 如果开启, Hibernate将收集有助于性能调节的统计数据.
取值 true | false
hibernate.use_identifer_rollback  如果开启, 在对象被删除时生成的标识属性将被重设为默认值.
取值 true | false
hibernate.use_sql_comments 如果开启, Hibernate将在SQL中生成有助于调试的注释信息, 默认值为false.
取值 true | false

表 4.4. Hibernate JDBC和连接(connection)属性

Hibernate JDBC和连接(connection)属性
属性名 用途
hibernate.jdbc.fetch_size 非零值,指定JDBC抓取数量的大小 (调用Statement.setFetchSize()).
hibernate.jdbc.batch_size 非零值,允许Hibernate使用JDBC2的批量更新.
取值 建议取5到30之间的值
hibernate.jdbc.batch_versioned_data 如果你想让你的JDBC驱动从executeBatch()返回正确的行计数 , 那么将此属性设为true(开启这个选项通常是安全的). 同时,Hibernate将为自动版本化的数据使用批量DML. 默认值为false.
eg. true | false
hibernate.jdbc.factory_class 选择一个自定义的Batcher. 多数应用程序不需要这个配置属性.
eg. classname.of.Batcher
hibernate.jdbc.use_scrollable_resultset 允许Hibernate使用JDBC2的可滚动结果集. 只有在使用用户提供的JDBC连接时,这个选项才是必要的, 否则Hibernate会使用连接的元数据.
取值 true | false
hibernate.jdbc.use_streams_for_binary 在JDBC读写binary (二进制)或serializable (可序列化) 的类型时使用流(stream)(系统级属性).
取值 true | false
hibernate.jdbc.use_get_generated_keys 在数据插入数据库之后,允许使用JDBC3 PreparedStatement.getGeneratedKeys() 来获取数据库生成的key(键)。需要JDBC3+驱动和JRE1.4+, 如果你的数据库驱动在使用Hibernate的标 识生成器时遇到问题,请将此值设为false. 默认情况下将使用连接的元数据来判定驱动的能力.
取值 true|false
hibernate.connection.provider_class 自定义ConnectionProvider的类名, 此类用来向Hibernate提供JDBC连接.
取值 classname.of.ConnectionProvider
hibernate.connection.isolation  设置JDBC事务隔离级别. 查看java.sql.Connection来了解各个值的具体意义, 但请注意多数数据库都不支持所有的隔离级别.
取值 1, 2, 4, 8
hibernate.connection.autocommit 允许被缓存的JDBC连接开启自动提交(autocommit) (不建议).
取值 true | false
hibernate.connection.release_mode 指定Hibernate在何时释放JDBC连接. 默认情况下,直到Session被显式关闭或被断开连接时,才会释放JDBC连接. 对于应用程序服务器的JTA数据源, 你应当使用after_statement, 这样在每次JDBC调用后,都会主动的释放连接. 对于非JTA的连接, 使用after_transaction在每个事务结束时释放连接是合理的. auto将为JTA和CMT事务策略选择after_statement, 为JDBC事务策略选择after_transaction.
取值 on_close | after_transaction | after_statement | auto
hibernate.connection.<propertyName> 将JDBC属性propertyName传递到DriverManager.getConnection()中去.
hibernate.jndi.<propertyName> 将属性propertyName传递到JNDI InitialContextFactory中去.

表 4.5. Hibernate缓存属性

Hibernate缓存属性
属性名 用途
hibernate.cache.provider_class 自定义的CacheProvider的类名.
取值 classname.of.CacheProvider
hibernate.cache.use_minimal_puts 以频繁的读操作为代价, 优化二级缓存来最小化写操作. 在Hibernate3中,这个设置对的集群缓存非常有用, 对集群缓存的实现而言,默认是开启的.
取值 true|false
hibernate.cache.use_query_cache 允许查询缓存, 个别查询仍然需要被设置为可缓存的.
取值 true|false
hibernate.cache.use_second_level_cache 能用来完全禁止使用二级缓存. 对那些在类的映射定义中指定<cache>的类,会默认开启二级缓存.
取值 true|false
hibernate.cache.query_cache_factory 自定义的实现QueryCache接口的类名, 默认为内建的StandardQueryCache.
取值 classname.of.QueryCache
hibernate.cache.region_prefix 二级缓存区域名的前缀.
取值 prefix
hibernate.cache.use_structured_entries 强制Hibernate以更人性化的格式将数据存入二级缓存.
取值 true|false

表 4.6. Hibernate事务属性

Hibernate事务属性
属性名 用途
hibernate.transaction.factory_class 一个TransactionFactory的类名, 用于Hibernate Transaction API (默认为JDBCTransactionFactory).
取值 classname.of.TransactionFactory
jta.UserTransaction 一个JNDI名字,被JTATransactionFactory用来从应用服务器获取JTA UserTransaction.
取值 jndi/composite/name
hibernate.transaction.manager_lookup_class 一个TransactionManagerLookup的类名 - 当使用JVM级缓存,或在JTA环境中使用hilo生成器的时候需要该类.
取值 classname.of.TransactionManagerLookup
hibernate.transaction.flush_before_completion 如果开启, session在事务完成后将被自动清洗(flush). (在Hibernate和CMT一起使用时很有用.)
取值 true | false
hibernate.transaction.auto_close_session 如果开启, session在事务完成后将被自动关闭. (在Hibernate和CMT一起使用时很有用.)
取值 true | false

表 4.7. 其他属性

其他属性
属性名 用途
hibernate.query.factory_class 选择HQL解析器的实现.
取值 org.hibernate.hql.ast.ASTQueryTranslatorFactory or org.hibernate.hql.classic.ClassicQueryTranslatorFactory
hibernate.query.substitutions 将Hibernate查询中的符号映射到SQL查询中的符号 (符号可能是函数名或常量名字).
取值 hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC
hibernate.hbm2ddl.auto 在SessionFactory创建时,自动将数据库schema的DDL导出到数据库. 使用 create-drop时,在显式关闭SessionFactory时,将drop掉数据库schema.
取值 update | create | create-drop
hibernate.cglib.use_reflection_optimizer 开启CGLIB来替代运行时反射机制(系统级属性). 反射机制有时在除错时比较有用. 注意即使关闭这个优化, Hibernate还是需要CGLIB. 你不能在hibernate.cfg.xml中设置此属性.
取值 true | false

4.4.1. SQL方言
你应当总是为你的数据库属性hibernate.dialect设置正确的 org.hibernate.dialect.Dialect子类. 如果你指定一种方言, Hibernate将为上面列出的一些属性使用合理的默认值, 为你省去了手工指定它们的功夫.

表 4.8. Hibernate SQL方言 (hibernate.dialect)

Hibernate SQL方言 (hibernate.dialect)
RDBMS 方言
DB2 org.hibernate.dialect.DB2Dialect
DB2 AS/400 org.hibernate.dialect.DB2400Dialect
DB2 OS390 org.hibernate.dialect.DB2390Dialect
PostgreSQL org.hibernate.dialect.PostgreSQLDialect
MySQL org.hibernate.dialect.MySQLDialect
MySQL with InnoDB org.hibernate.dialect.MySQLInnoDBDialect
MySQL with MyISAM org.hibernate.dialect.MySQLMyISAMDialect
Oracle (any version) org.hibernate.dialect.OracleDialect
Oracle 9i/10g org.hibernate.dialect.Oracle9Dialect
Sybase org.hibernate.dialect.SybaseDialect
Sybase Anywhere org.hibernate.dialect.SybaseAnywhereDialect
Microsoft SQL Server org.hibernate.dialect.SQLServerDialect
SAP DB org.hibernate.dialect.SAPDBDialect
Informix org.hibernate.dialect.InformixDialect
HypersonicSQL org.hibernate.dialect.HSQLDialect
Ingres org.hibernate.dialect.IngresDialect
Progress org.hibernate.dialect.ProgressDialect
Mckoi SQL org.hibernate.dialect.MckoiDialect
Interbase org.hibernate.dialect.InterbaseDialect
Pointbase org.hibernate.dialect.PointbaseDialect
FrontBase org.hibernate.dialect.FrontbaseDialect
Firebird org.hibernate.dialect.FirebirdDialect

4.4.2. 外连接抓取(Outer Join Fetching)
如果你的数据库支持ANSI, Oracle或Sybase风格的外连接, 外连接抓取常能通过限制往返数据库次数 (更多的工作交由数据库自己来完成)来提高效率. 外连接允许在单个SELECTSQL语句中, 通过many-to-one, one-to-many, many-to-many和one-to-one关联获取连接对象的整个对象图.

将hibernate.max_fetch_depth设为0能在全局 范围内禁止外连接抓取. 设为1或更高值能启用one-to-one和many-to-oneouter关联的外连接抓取, 它们通过 fetch="join"来映射.

参见第 20.1 节 “ 抓取策略(Fetching strategies) ”获得更多信息.

4.4.3. 二进制流 (Binary Streams)
Oracle限制那些通过JDBC驱动传输的字节数组的数目. 如果你希望使用二进值 (binary)或 可序列化的 (serializable)类型的大对象, 你应该开启 hibernate.jdbc.use_streams_for_binary属性. 这是系统级属性.

4.4.4. 二级缓存与查询缓存
以hibernate.cache为前缀的属性允许你在Hibernate中,使用进程或群集范围内的二级缓存系统. 参见第 20.2 节 “二级缓存(The Second Level Cache) ”获取更多的详情.

4.4.5. 查询语言中的替换
你可以使用hibernate.query.substitutions在Hibernate中定义新的查询符号. 例如:

hibernate.query.substitutions true=1, false=0
将导致符号true和false在生成的SQL中被翻译成整数常量.

hibernate.query.substitutions toLowercase=LOWER
将允许你重命名SQL中的LOWER函数.

4.4.6. Hibernate的统计(statistics)机制
如果你开启hibernate.generate_statistics, 那么当你通过 SessionFactory.getStatistics()调整正在运行的系统时,Hibernate将导出大量有用的数据. Hibernate甚至能被配置成通过JMX导出这些统计信息. 参考org.hibernate.stats中接口的Javadoc,以获得更多信息.

4.5. 日志

Hibernate使用Apache commons-logging来为各种事件记录日志.

commons-logging将直接输出到Apache Log4j(如果在类路径中包括log4j.jar)或 JDK1.4 logging (如果运行在JDK1.4或以上的环境下). 你可以从http://jakarta.apache.org 下载Log4j. 要使用Log4j,你需要将log4j.properties文件放置在类路径下, 随Hibernate 一同分发的样例属性文件在src/目录下.

我们强烈建议你熟悉一下Hibernate的日志消息. 在不失可读性的前提下, 我们做了很多工作,使Hibernate的日志可能地详细. 这是必要的查错利器. 最令人感兴趣的日志分类有如下这些:

表 4.9. Hibernate日志类别

Hibernate日志类别
类别 功能
org.hibernate.SQL 在所有SQL DML语句被执行时为它们记录日志
org.hibernate.type 为所有JDBC参数记录日志
org.hibernate.tool.hbm2ddl  在所有SQL DDL语句执行时为它们记录日志
org.hibernate.pretty 在session清洗(flush)时,为所有与其关联的实体(最多20个)的状态记录日志
org.hibernate.cache 为所有二级缓存的活动记录日志
org.hibernate.transaction 为事务相关的活动记录日志
org.hibernate.jdbc 为所有JDBC资源的获取记录日志
org.hibernate.hql.ast 为HQL和SQL的自动状态转换和其他关于查询解析的信息记录日志
org.hibernate.secure 为JAAS认证请求做日志
org.hibernate 为任何Hibernate相关信息做日志 (信息量较大, 但对查错非常有帮助)

在使用Hibernate开发应用程序时, 你应当总是为org.hibernate.SQL 开启debug级别的日志记录,或者开启hibernate.show_sql属性来代替它。.

4.6. 实现NamingStrategy

org.hibernate.cfg.NamingStrategy接口允许你为数据库中的对象和schema 元素指定一个“命名标准”.

你可能会提供一些通过Java标识生成数据库标识或将映射定义文件中"逻辑"表/列名处理成"物理"表/列名的规则. 这个特性有助于减少冗长的映射定义文件.

在加入映射定义前,你可以调用 Configuration.setNamingStrategy()指定一个不同的命名策略:

SessionFactory sf = new Configuration()
.setNamingStrategy(ImprovedNamingStrategy.INSTANCE)
.addFile("Item.hbm.xml")
.addFile("Bid.hbm.xml")
.buildSessionFactory();

org.hibernate.cfg.ImprovedNamingStrategy是一个内建的命名策略, 对 一些应用程序而言,可能是非常有用的起点.

4.7. XML配置文件

另一个配置方法是在hibernate.cfg.xml文件中指定一套完整的配置. 这个文件可以当成hibernate.properties的替代。 若两个文件同时存在,它将重载前者的属性.

XML配置文件被默认是放在CLASSPATH的根目录下. 这是一个例子:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<!-- 以/jndi/name绑定到JNDI的SessionFactory实例 -->
<session-factory
name="java:hibernate/SessionFactory">
<!-- 属性 -->
<property name="connection.datasource">java:/comp/env/jdbc/MyDB</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">false</property>
<property name="transaction.factory_class">
org.hibernate.transaction.JTATransactionFactory
</property>
<property name="jta.UserTransaction">java:comp/UserTransaction</property>
<!-- 映射定义文件 -->
<mapping resource="org/hibernate/auction/Item.hbm.xml"/>
<mapping resource="org/hibernate/auction/Bid.hbm.xml"/>
<!-- 缓存设置 -->
<class-cache class="org.hibernate.auction.Item" usage="read-write"/>
<class-cache class="org.hibernate.auction.Bid" usage="read-only"/>
<collection-cache class="org.hibernate.auction.Item.bids" usage="read-write"/>
</session-factory>
</hibernate-configuration>

如你所见, 这个方法优势在于,在配置文件中指出了映射定义文件的名字. 一旦你需要调整Hibernate的缓存, hibernate.cfg.xml也是更方便. 注意,使用hibernate.properties还是 hibernate.cfg.xml完全是由你来决定, 除了上面提到的XML语法的优势之外, 两者是等价的.

使用XML配置,使得启动Hibernate变的异常简单, 如下所示,一行代码就可以搞定:

SessionFactory sf = new Configuration().configure().buildSessionFactory();
你可以使用如下代码来添加一个不同的XML配置文件

SessionFactory sf = new Configuration()
.configure("catdb.cfg.xml")
.buildSessionFactory();
4.8. J2EE应用程序服务器的集成

针对J2EE体系,Hibernate有如下几个集成的方面:

容器管理的数据源(Container-managed datasources): Hibernate能通过容器管理由JNDI提供的JDBC连接. 通常, 特别是当处理多个数据源的分布式事务的时候, 由一个JTA兼容的TransactionManager和一个 ResourceManager来处理事务管理(CMT, 容器管理的事务). 当然你可以通过 编程方式来划分事务边界(BMT, Bean管理的事务). 或者为了代码的可移植性,你也也许会想使用可选的 Hibernate Transaction API.

自动JNDI绑定: Hibernate可以在启动后将 SessionFactory绑定到JNDI.

JTA Session绑定: 如果使用EJB, Hibernate Session 可以自动绑定到JTA事务作用的范围. 只需简单地从JNDI查找SessionFactory并获得当前的 Session. 当JTA事务完成时, 让Hibernate来处理 Session的清洗(flush)与关闭. 在EJB的部署描述符中事务边界是声明式的.

JMX部署: 如果你使用支持JMX应用程序服务器(如, JBoss AS), 那么你可以选择将Hibernate部署成托管MBean. 这将为你省去一行从Configuration构建SessionFactory的启动代码. 容器将启动你的HibernateService, 并完美地处理好服务间的依赖关系 (在Hibernate启动前,数据源必须是可用的等等).

如果应用程序服务器抛出"connection containment"异常, 根据你的环境,也许该将配置属性 hibernate.connection.release_mode设为after_statement.

4.8.1. 事务策略配置
在你的架构中,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的一些特性 (即二级缓存, JTA与Session的自动绑定等等)需要访问在托管环境中的JTA TransactionManager. 由于J2EE没有标准化一个单一的机制,Hibernate在应用程序服务器中,你必须指定Hibernate如何获得TransactionManager的引用:

表 4.10. JTA TransactionManagers

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

4.8.2. JNDI绑定的SessionFactory
与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. 请注意, 如果你使用第一章中介绍的帮助类HibernateUtil - 类似Singleton(单实例)注册表, 那么这里的启动代码不是必要的. 但HibernateUtil更多被使用在非托管环境中.

4.8.3. JTA和Session的自动绑定
在非托管环境中,我们建议:HibernateUtil和静态SessionFactory一起工作, 由ThreadLocal管理Hibernate Session。 由于一些EJB可能会运行在同一个事务但不同线程的环境中, 所以这个方法不能照搬到EJB环境中. 我们建议在托管环境中,将SessionFactory绑定到JNDI上.

请使用SessionFactory的getCurrentSession()方法来代替 直接使用ThreadLocal去获得Hibernate Session. 如果在当前JTA事务中没有Hibernate Session, 将会启动一个并将它关联到事务中. 对于使用getCurrentSession()获得的每个Session而言, hibernate.transaction.flush_before_completion 和hibernate.transaction.auto_close_session这两个配置选项会自动设置, 因此在容器结束JTA事务时,这些Session会被自动清洗(flush)并关闭.

例如,如果你使用DAO模式来编写你的持久层, 那么在需要时,所有DAO将查找SessionFactory并打开"当前"Session. 没有必要在控制代码和DAO代码间传递SessionFactory或Session的实例.

4.8.4. JMX部署
为了将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部署的信息.