转载: Hibernate中SessionFactory配置

SessionFactory配置

因为Hibernate被设计为可以在许多不同环境下工作,所以它有很多配置参数。幸运的是,大部分都已经有默认值了,Hibernate发行包中还附带有示例的hibernate.properties文件,它演示了一些可变的参数。一般你只需要把这个文件放到你的classpath,配置一下即可。

1. 可编程配置方式

net.sf.hibernate.cfg.Configuration的一个实例代表了应用程序中所有的Java类到SQL数据库的映射的集合。Configuration用于构造一个(不可变的)SessionFactory。这些映射是从一些XML映射文件中编译得来的。

你可以得到一个Configuration的实例,直接实例化它即可。下面有一个例子,用来从两个XML配置文件(位于classpath)中的映射中初始化:

Configuration cfg = new Configuration()
    .addFile("Item.hbm.xml")
    .addFile("Bid.hbm.xml");

另外一个(某些时候更好的)方法是让Hibernate自行用getResourceAsStream()来装载映射文件。

Configuration cfg = new Configuration()
    .addClass(org.hibernate.auction.Item.class)
    .addClass(org.hibernate.auction.Bid.class);

Hibernate 就会在classpath中寻找叫做/org/hibernate/autcion/Item.hbm.xml、/org/hibernate/autcion/Bid.hbm.xml的映射文件。这种方法取消了所有对文件名的硬编码。

Configuration也可以指定一些可选的配置项:

Properties props = new Properties();
...
Configuration cfg = new Configuration()
    .addClass(org.hibernate.auction.Item.class)
    .addClass(org.hibernate.auction.Bid.class)
    .setProperties(props);

Configuration是仅在配置期使用的对象,从第一个SessionFactory开始建立的时候,它就失效了。

2. 获取SessionFactory

当所有的映射都被Configuration解析之后,应用程序为了得到Session实例,必须先得到它的工厂。这个工厂应该是被应用程序的所有线程共享的:

SessionFactory sessions = cfg.buildSessionFactory();

当然,Hibernate并不禁止你的程序实例化多个SessionFactory。在你使用不止一个数据库的时候,这就有用了。

3. 用户自行提供JDBC连接

SessionFactory可以使用一个用户自行提供的JDBC连接来打开一个Session。这种设计可以让应用程序来自己管理JDBC连接:

java.sql.Connection conn = datasource.getConnection();
Session session = sessions.openSession(conn);

// do some data access work

应用程序必须小心,不能在同一个连接上打开两个并行的session!

4. Hibernate提供的JDBC连接

另一种方法就是,你可以让SessionFactory替你打开连接。SessionFactory必须事先知道JDBC连接的参数,有几种不同的方法设置参数:

  1. 传递一个java.util.Properties到Configuration.setProperties()方法。

  2. 在classpath的根目录中提供hibernate.properties文件。

  3. 通过java -Dproperty=value指定使用系统属性。

  4. 在hibernate.cfg.xml文件中包含<property>元素。详情见后。

如果你使用这种方法,打开一个Session是非常简单的:

Session session = sessions.openSession(); // open a new Session
// do some data access work, a JDBC connection will be used on demand

所有的Hibernate属性名和约束都在net.sf.hibernate.cfg.Environment类中定义。我们讨论一下JDBC连接配置最重要的几项设置:

假若你设置了如下的属性,Hibernate会使用java.sql.DriverManager来得到连接,并建立连接池:

表 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属性。

C3P0是随Hibernate发行包一起发布的一个开放源代码JDBC连接池,你可以在lib 目录中找到。假若你设置了hibernate.c3p0.* 属性,Hibernate会使用内置的C3P0ConnectionProvider作为连接池。 对Apache DBCP和Proxool的支持也是内置的。你必须设置hibernate.dbcp.*属性 (DBCP连接池属性)来打开DBCPConnectionProvider。如果打开hibernate.dbcp.ps.* (DBCP 语句缓存属性)可以使用Prepared statement缓存(高度推荐)。要知道它们的含义,请查阅Apache commons-pool的文档。如果你想要用Proxool,你需要设置hibernate.proxool.*系列属性。

下面是使用C3P0的一个例子:

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 = net.sf.hibernate.dialect.PostgreSQLDialect

在Application Server内使用时,Hibernate可以从JNDI中注册的javax.sql.Datasource取得连接。需要设置如下属性:

表 3.2. Hibernate 数据源(Datasource)属性

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

下面是一个使用应用服务器提供的JNDI数据源的例子:

hibernate.connection.datasource = java:/comp/env/jdbc/MyDB
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

从JNDI数据源获得的JDBC连接自动具有应用服务器的容器管理事务的特性。

可以通过"hibernate.connnection"开头的属性来设置特别的连接属性。比如,你可以通过hibernate.connnection.charSet来指定charSet。

通过实现net.sf.hibernate.connection.ConnectionProvider接口,你可以定义如何获得JDBC连接的策略。你可以通过设置hibernate.connection.provider_class来选择一个自定义的实现。

5. 可选配置属性

下面是一些在运行时可以改变Hibernate行为的其他配置。所有这些都是可选的,也有合理的默认值。

系统级别的配置只能通过java -Dproperty=value或者在hibernate.properties文件中配置,而不能通过传递给Configuration的Properties实例来配置。

表 3.3. Hibernate配置属性

属性名 用途
hibernate.dialect Hibernate方言(Dialect)的类名 - 可以让Hibernate使用某些特定的数据库平台的特性

取值. full.classname.of.Dialect

hibernate.default_schema 在生成的SQL中,scheml/tablespace的全限定名

取值. SCHEMA_NAME

hibernate.session_factory_name 自动把创建的SessionFactory以这个名字绑定到JNDI中去.

取值. jndi/composite/name

hibernate.use_outer_join 允许使用外连接抓取。已经失效。请使用max_fetch_depth。

取值. true | false

hibernate.max_fetch_depth 对单根联合(一对一,多对一),设置外连接抓取树的最大深度。如果是0将关闭默认的外连接抓取。

取值. 建议设置为0到3之间

hibernate.jdbc.fetch_size 一个非零值,用来决定JDBC的获取量大小。(会调用Statement.setFetchSize()).
hibernate.jdbc.batch_size 一个非零值,会开启Hibernate使用JDBC2的批量更新功能

取值. 建议值在 5 和 30之间。

hibernate.jdbc.use_scrollable_resultset 允许Hibernate使用JDBC2提供的可滚动结果集。只有在使用用户自行提供的JDBC连接时,这个参数才是必需的。否则Hibernate会使用连接的元数据(metadata)。

取值. 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。默认情况下,会用connection元数据根据驱动是否支持自动判断。

取值. true|false

hibernate.cglib.use_reflection_optimizer 是否使用CGLIB来代替运行时反射操作。(系统级别属性,默认为在可能时都使用CGLIB).在调试的时候有时候使用反射会有用。

取值. true | false

hibernate.jndi.<propertyName> 把propertyName这个属性传递到JNDI InitialContextFactory去 (可选)
hibernate.connection.isolation 事务隔离级别 (可选).请检查java.sql.Connection来得到取值的具体意义。注意大多数数据库不会支持所有的隔离级别。

取值. 1, 2, 4, 8

hibernate.connection.<propertyName> 把 propertyName这个JDBC 属性传递到DriverManager.getConnection()去
hibernate.connection.provider_class 指定一个自定义的ConnectionProvider类名

取值. classname.of.ConnectionProvider

hibernate.cache.provider_class 指定一个自定义的CacheProvider缓存提供者的类名

取值. classname.of.CacheProvider

hibernate.cache.use_minimal_puts 优化第二级缓存操作,减少写操作,代价是读操作更频繁(对于集群缓存很有用)

取值. true|false

hibernate.cache.use_query_cache 打开查询缓存,每个查询仍然必须指明cacheable。

取值. true|false

hibernate.cache.region_prefix 用于第二级缓存区域名字的前缀

取值. prefix

hibernate.transaction.factory_class 指定一个自定义的TransactionFactory类名,Hibernate Transaction API将会使用(默认是JDBCTransactionFactory)。

取值. classname.of.TransactionFactory

jta.UserTransaction JTATransactionFactory 用来从应用服务器获取JTAUserTransaction的JNDI名

取值. jndi/composite/name

hibernate.transaction.manager_lookup_class TransactionManagerLookup的类名 - 当在JTA环境中,JVM级别的缓存被打开的时候使用.

取值. classname.of.TransactionManagerLookup

hibernate.query.substitutions 把Hibernate查询中的一些短语替换为SQL短语(比如说短语可能是函数或者字符)。

取值. hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC

hibernate.show_sql 把所有的SQL语句都输出到控制台

取值. true | false

hibernate.hbm2ddl.auto 在SessionFactory创建后,自动输出schema创建DDL语句到数据库.和create-drop同时使用的话,数据库schema会在SessionFactory显式关闭后被drop掉。

取值. update | create | create-drop

5.1. SQL Dialects SQL 方言

你总是可以为你的数据库设置一个hibernate.dialect方言,它是net.sf.hibernate.dialect.Dialect 的一个子类。如果你不需要使用基于native或者sequence的主键自动生成算法,或者悲观锁定(使用Session.lock() 或Query.setLockMode())的话,方言就可以不必指定。然而,假若你指定了一个方言,Hibernate会为上面列出的一些属性使用特殊默认值,省得你手工指定它们。

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

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

5.2. 外连接抓取(Outer Join Fetching )

如果你的数据库支持ANSI或者Oracle风格的外连接,外连接抓取可能提高性能,因为可以限制和数据库交互的数量(代价是数据库自身进行了更多的工作)。外连接抓取允许你在一个select语句中就可以得到一个由多对一或者一对一连接构成的对象图。

默认情况下,抓取在叶对象,拥有代理的对象或者产生对自身的引用时终止。

对一个特定关联来说,通过在XML映射文件中设置outer-join属性可以控制是否开启抓取功能。

也可以设置hibernate.max_fetch_depth为0来全局关闭此功能。如果设置为1或更高的数值,对所有的一对一和多对一关联会打开外连接抓取。默认情况下,它被设置为auto,即自动外连接。但是,一对多关联和集合永远不会使用外连接抓取,除非对每个特定的关联进行明确声明。这一行为可以在运行时通过Hibernate 查询重载。

5.3. 二进制流

Oracle限制通过它的JDBC驱动传递的byte数组的大小。如果你希望使用很大数量的binary或者serializable 类型的话,你需要打开hibernate.jdbc.use_streams_for_binary。这只能通过JVM级别设定

5.4. 自定义CacheProvider

通过实现net.sf.hibernate.cache.CacheProvider接口,你可以整合一个JVM级别(或者集群的)第二级缓存进来。你可以通过hibernate.cache.provider_class选择某个自定义的实现。

5.5. 事务策略配置

如果你希望使用Hibernate的Transaction API,你必须通过hibernate.transaction.factory_class属性指定一个Transaction实例的工厂类。 Transaction API隐藏了底层的事务机制,允许Hibernate代码在受管制和非受管制的环境下都可以运行。

内置的两个标准选择是:

net.sf.hibernate.transaction.JDBCTransactionFactory

使用数据库(JDBC)事务(默认)

net.sf.hibernate.transaction.JTATransactionFactory

使用JTA(假若已经存在一个事务,Session会在这个上下文中工作,否则会启动一个新的事务。)

你也可以自行定义你的事务策略(比如说,一个CORBA事务服务)。

如果你希望在JTA环境中为可变数据使用JVM级别的缓存,你必须指定一个获取JTA TransactionManager的策略,但这对J2EE容易来说不是标准化的:

表 3.5. JTA TransactionManagers

事务工厂类 Application Server
net.sf.hibernate.transaction.JBossTransactionManagerLookup JBoss
net.sf.hibernate.transaction.WeblogicTransactionManagerLookup Weblogic
net.sf.hibernate.transaction.WebSphereTransactionManagerLookup WebSphere
net.sf.hibernate.transaction.OrionTransactionManagerLookup Orion
net.sf.hibernate.transaction.ResinTransactionManagerLookup Resin
net.sf.hibernate.transaction.JOTMTransactionManagerLookup JOTM
net.sf.hibernate.transaction.JOnASTransactionManagerLookup JOnAS
net.sf.hibernate.transaction.JRun4TransactionManagerLookup JRun4
net.sf.hibernate.transaction.BESTransactionManagerLookup Borland ES

5.6. 绑定SessionFactory到JNDI

绑定到JNDI的Hibernate SessionFactory可以简化查找工厂和创建新Session的过程。

假若你希望把SessionFactory绑定到一个JNDI命名空间,用hibernate.session_factory_name这个属性指定一个名字(比如,java:comp/env/hibernate/SessionFactory)。如果这个属性省略了,SessionFactory不会被绑定到JNDI。(在一个只读的JNDI默认值实现的环境中,这特别有用。比如,Tomcat。)

当把SessionFactory 绑定到JNDI,Hibernate会使用hibernate.jndi.url,hibernate.jndi.class的值来获得一个初始化上下文的实例。如果他们没有指定,就会使用默认的InitialContext。

如果你选择使用JNDI,EJB或者其他工具类就可以通过JNDI查询得到SessionFactory。

5.7. 查询语言替换

你可以使用hibernate.query.substitutions定义新的Hibernate查询短语。比如说:

hibernate.query.substitutions true=1, false=0

会在生成的SQL中把短语true和 false替换成整数值。

hibernate.query.substitutions toLowercase=LOWER

这可以让你重新命名SQL的LOWER函数。

6. Logging

通过Apache commons-logging,Hibernate记录很多事件。

commons-logging服务会直接输出到Apache log4j(如果你把log4j.jar放在你的classpath里),或者JDK1.4 logging(如果你运行JDK 1.4或以上版本)。你可以从http://jakarta.apache.org下载log4j。要使用log4j,你需要在你的classpath中放置一个log4j.properties文件。Hibernate发行包中包含一个示例的properties配置文件。

我们强烈建议你熟悉Hibernate的log信息。Hibernate的很多工作都会尽量详细的留下log,也没有让它变的难以阅读。这是用来解决问题的最基本的设施。当然也别忘了可以如前所述打开SQL 记录(hibernate.show_sql),在你要解决性能问题时,这是你第一步就需要做的。

7. 实现NamingStrategy(命名策略)

net.sf.hibernate.cfg.NamingStrategy接口允许你对数据库对象和schema元素指定“命名标准”。

你可以定义从Java标识符自动生成数据库标识符的规则,或者是映射文件中给出的“逻辑”字段名和表名处理为“物理”表名和字段名的规则。这个功能可以让映射文件变得简洁,消除无用的噪音(比如TBL_前缀等)。Hibernate使用的默认策略是几乎什么都不做。

你可以在增加映射(add mappings)之前调用Configuration.setNamingStrategy()来指定不同的策略。

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

net.sf.hibernate.cfg.ImprovedNamingStrategy 是一个内置的策略,对某些程序,你可以把它作为改造的起点。

8. XML配置文件

另一种配置属性的方法是把所有的配置都放在一个名为hibernate.cfg.xml的文件中。这个文件可以被用于替代hibernate.properties文件,如果二者都出现,它会覆盖properties文件。

XML配置文件默认会期望在CLASSPATH的根目录中找到。下面是一个例子。

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 2.0//EN"

 "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">

<hibernate-configuration>

    <!-- a SessionFactory instance listed as /jndi/name -->
    <session-factory
        name="java:comp/env/hibernate/SessionFactory">

        <!-- properties -->
        <property name="connection.datasource">my/first/datasource</property>
        <property name="dialect">net.sf.hibernate.dialect.MySQLDialect</property>
        <property name="show_sql">false</property>
        <property name="use_outer_join">true</property>
        <property name="transaction.factory_class">
            net.sf.hibernate.transaction.JTATransactionFactory
        </property>
        <property name="jta.UserTransaction">java:comp/UserTransaction</property>

        <!-- mapping files -->
        <mapping resource="org/hibernate/auction/Item.hbm.xml"/>
        <mapping resource="org/hibernate/auction/Bid.hbm.xml"/>

    </session-factory>

</hibernate-configuration>

配置Hibernate只需如此简单:

SessionFactory sf = new Configuration().configure().buildSessionFactory();

你可以使用另外一个名字的XML配置文件:

SessionFactory sf = new Configuration()
    .configure("catdb.cfg.xml")
    .buildSessionFactory();

你可能感兴趣的:(java,Hibernate)