Hibernate配置文件可以有两种格式,一种是 hibernate.properties ,另一种是 hibernate.cfg.xml
后者稍微方便一些,当增加hbm映射文件的时候,可以直接在 hibernate.cfg.xml 里面增加,不必像 hibernate.properties 必须在初始化代码中加入。
但不管怎么说,两种的配置项都是一样的,下面详细介绍:
在Hibernate的src目录下有一个 hibernate.properties 模板,我们不必自己从头写,修改模板就可以了:)
hibernate.query.substitutions true 1, false 0, yes 'Y', no 'N'
这个配置意思是当你在Hibernate里面输入true的时候,Hibernate会转化为1插入数据库,当你在Hibernate里面输入false的时候,Hibernate会转化为0插入数据库,后面的Y,N同理。
对于某些数据库,例如Oracle来说,没有boolean数据类型,就是采用1代表true,0代表false,因此使用这个配置在Hibernate里面直接用true/false会非常直观。
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class com.mysql.jdbc.Driver
hibernate.connection.url jdbc:mysql:///test
hibernate.connection.username root
hibernate.connection.password
这是一个连接MySQL数据库的例子,很直观,不必解释,不同的数据库的连接参数模板中全部给出了。
hibernate.connection.pool_size 1
hibernate.statement_cache.size 25
这是Hibernate自带的连接池的配置参数,在默认情况下将采用。意义很直观,不多解释。
只是提醒一点,Hibernate这个连接池是非常原始非常简单的连接池,如果你在项目中用Hibernate的话,建议你首选App Server的连接池,次选Hibernate带的DBCP连接池。自带的连接池应该做为末选。
如果你采用DBCP连接池,除了要配置DBCP连接池以外,还需要取消掉下行的注释:
hibernate.connection.provider_class net.sf.hibernate.connection.DBCPConnectionProvider
其它的连接池同理。
如果采用App Server的连接池,假设App Server连接池的DataSource的JNDI名称为"mypool"的话,配置应该如下:
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect
hibernate.connection.datasource mypool
hibernate.connection.provider_class net.sf.hibernate.connection.DatasourceConnectionProvider
其它参数就不必写了,因为已经在App Server配置连接池的时候指定好了。
如果你不是在App Server环境中使用Hibernate,例如远程客户端程序,但是你又想用App Server的数据库连接池,那么你还需要配置JNDI的参数,例如Hibernate连接远程Weblogic上的数据库连接池:
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect
hibernate.connection.datasource mypool
hibernate.connection.provider_class net.sf.hibernate.connection.DatasourceConnectionProvider
hibernate.jndi.class weblogic.jndi.WLInitialContextFactory
hibernate.jndi.url t3://servername:7001/
最后,如果你需要在EJB或者JTA中使用Hibernate,需要取消下行的注释:
hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
杂项配置:
hibernate.show_sql false
是否将Hibernate发送给数据库的sql显示出来,这是一个非常非常有用处的功能。当你在调试Hibernate的时候,让Hibernate打印sql语句,可以帮助你迅速解决问题。
#hibernate.connection.isolation 4
指定数据库的隔离级别,往往不同的数据库有自己定义的隔离级别,未必是Hibernate的设置所能更改的,所以也不必去管它了。
hibernate.jdbc.fetch_size 50
hibernate.jdbc.batch_size 25
这两个选项非常非常非常重要!!!将严重影响Hibernate的CRUD性能!
C = create, R = read, U = update, D = delete
Fetch Size 是设定JDBC的Statement读取数据的时候每次从数据库中取出的记录条数。
例如一次查询1万条记录,对于Oracle的JDBC驱动来说,是不会1次性把1万条取出来的,而只会取出Fetch Size条数,当纪录集遍历完了这些记录以后,再去数据库取Fetch Size条数据。
因此大大节省了无谓的内存消耗。当然Fetch Size设的越大,读数据库的次数越少,速度越快;Fetch Size越小,读数据库的次数越多,速度越慢。
这有点像平时我们写程序写硬盘文件一样,设立一个Buffer,每次写入Buffer,等Buffer满了以后,一次写入硬盘,道理相同。
Oracle数据库的JDBC驱动默认的Fetch Size=10,是一个非常保守的设定,根据我的测试,当Fetch Size=50的时候,性能会提升1倍之多,当Fetch Size=100,性能还能继续提升20%,Fetch Size继续增大,性能提升的就不显著了。
因此我建议使用Oracle的一定要将Fetch Size设到50。
不过并不是所有的数据库都支持Fetch Size特性,例如MySQL就不支持。
MySQL就像我上面说的那种最坏的情况,他总是一下就把1万条记录完全取出来,内存消耗会非常非常惊人!这个情况就没有什么好办法了 :(
Batch Size是设定对数据库进行批量删除,批量更新和批量插入的时候的批次大小,有点相当于设置Buffer缓冲区大小的意思。
Batch Size越大,批量操作的向数据库发送sql的次数越少,速度就越快。我做的一个测试结果是当Batch Size=0的时候,使用Hibernate对Oracle数据库删除1万条记录需要25秒,Batch Size = 50的时候,删除仅仅需要5秒!!!
可见有多么大的性能提升!很多人做Hibernate和JDBC的插入性能测试会奇怪的发现Hibernate速度至少是JDBC的两倍,就是因为Hibernate使用了Batch Insert,而他们写的JDBC没有使用Batch的缘故。
以我的经验来看,Oracle数据库 Batch Size = 30 的时候比较合适,50也不错,性能会继续提升,50以上,性能提升的非常微弱,反而消耗内存更加多,就没有必要了。
#hibernate.jdbc.use_scrollable_resultset true
设定是否可以使用JDBC2.0规范的可滚动结果集,这对Hibernate的分页显示有一定的作用,默认就好了。
#hibernate.cglib.use_reflection_optimizer false
默认打开,启用cglib反射优化。cglib是用来在Hibernate中动态生成PO字节码的,打开优化可以加快字节码构造的速度。
不过,当你在调试程序过程中,特别是和proxy,lazy loading相关的应用中,代码出错,但是出错提示信息有语焉不详,那么你可以把cglib优化关掉,这样Hibernate会输出比较详细的调试信息,帮助你debug。
一个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创建完成它就被丢弃了.
当所有映射定义被Configuration解析后, 应用程序必须获得一个用于构造Session实例的工厂. 这个工厂将被应用程序的所有线程共享:
SessionFactory sessions = cfg.buildSessionFactory();
Hibernate允许你的应用程序创建多个SessionFactory实例. 这对 使用多个数据库的应用来说很有用.
通常你希望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连接 :
表 3.1. 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处获得连接,你至少需要设置下列属性中的一个:
表 3.2. 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, 你可以选择一个自定义的实现.
有大量属性能用来控制Hibernate在运行期的行为. 它们都是可选的, 并拥有适当的默认值.
警告: 其中一些属性是"系统级(system-level)的". 系统级属性可以通过java -Dproperty=value或 hibernate.properties来设置, 而不能用上面描述的其他方法来设置.
表 3.3. 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 |
表 3.4. 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中去. |
表 3.5. 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 |
表 3.6. 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 |
表 3.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 |
你应当总是为你的数据库属性hibernate.dialect设置正确的 org.hibernate.dialect.Dialect子类. 如果你指定一种方言, Hibernate将为上面列出的一些属性使用合理的默认值, 为你省去了手工指定它们的功夫.
表 3.8. 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 |
如果你的数据库支持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"来映射.
Oracle限制那些通过JDBC驱动传输的字节数组的数目. 如果你希望使用二进值 (binary)或 可序列化的 (serializable)类型的大对象, 你应该开启 hibernate.jdbc.use_streams_for_binary属性. 这是系统级属性.
以hibernate.cache为前缀的属性允许你在Hibernate中,使用进程或群集范围内的二级缓存系统. 参见第 19.2 节 “二级缓存(The Second Level Cache) ”获取更多的详情.
你可以使用hibernate.query.substitutions在Hibernate中定义新的查询符号. 例如:
hibernate.query.substitutions true=1, false=0
将导致符号true和false在生成的SQL中被翻译成整数常量.
hibernate.query.substitutions toLowercase=LOWER
将允许你重命名SQL中的LOWER函数.
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的日志可能地详细. 这是必要的查错利器. 最令人感兴趣的日志分类有如下这些:
表 3.9. 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属性来代替它。.
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是一个内建的命名策略, 对 一些应用程序而言,可能是非常有用的起点.
另一个配置方法是在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();
针对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.
在你的架构中,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的引用:
表 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. 请注意, 如果你使用第一章中介绍的帮助类HibernateUtil - 类似Singleton(单实例)注册表, 那么这里的启动代码不是必要的. 但HibernateUtil更多被使用在非托管环境中.
在非托管环境中,我们建议: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的实例.
为了将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部署的信息.