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。

解决方案 »

  1.   

    学hibernate不是学习怎么配置,而是学习他的思想,摘自www.hibernate.org.cn
      

  2.   

    Hibernate入门 - 包作用详解
    Hibernate一共包括了23个jar包,令人眼花缭乱。本文将详细讲解Hibernate每个jar包的作用,便于你在应用中根据自己的需要进行取舍。 
    下载Hibernate,例如2.0.3稳定版本,解压缩,可以看到一个hibernate2.jar和lib目录下有22个jar包: 
    · hibernate2.jar: 
    Hibernate的库,没有什么可说的,必须使用的jar包 
    · cglib-asm.jar: 
    CGLIB库,Hibernate用它来实现PO字节码的动态生成,非常核心的库,必须使用的jar包 
    · dom4j.jar: 
    dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的。dom4j是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件,可以在SourceForge上找到它。在IBM developerWorks上面可以找到一篇文章,对主流的Java XML API进行的性能、功能和易用性的评测,dom4j无论在那个方面都是非常出色的。我早在将近两年之前就开始使用dom4j,直到现在。如今你可以看到越来越多的Java软件都在使用dom4j来读写XML,特别值得一提的是连Sun的JAXM也在用dom4j。这是必须使用的jar包,Hibernate用它来读写配置文件。 
    · odmg.jar: 
    ODMG是一个ORM的规范,Hibernate实现了ODMG规范,这是一个核心的库,必须使用的jar包。 
    · commons-collections.jar: 
    Apache Commons包中的一个,包含了一些Apache开发的集合类,功能比java.util.*强大。必须使用的jar包。 
    · commons-beanutils.jar: 
    Apache Commons包中的一个,包含了一些Bean工具类类。必须使用的jar包。 
    · commons-lang.jar: 
    Apache Commons包中的一个,包含了一些数据类型工具类,是java.lang.*的扩展。必须使用的jar包。 
    · commons-logging.jar: 
    Apache Commons包中的一个,包含了日志功能,必须使用的jar包。这个包本身包含了一个Simple Logger,但是功能很弱。在运行的时候它会先在CLASSPATH找log4j,如果有,就使用log4j,如果没有,就找JDK1.4带的java.util.logging,如果也找不到就用Simple Logger。commons-logging.jar的出现是一个历史的的遗留的遗憾,当初Apache极力游说Sun把log4j加入JDK1.4,然而JDK1.4项目小组已经接近发布JDK1.4产品的时间了,因此拒绝了Apache的要求,使用自己的java.util.logging,这个包的功能比log4j差的很远,性能也一般。后来Apache就开发出来了commons-logging.jar用来兼容两个logger。因此用commons-logging.jar写的log程序,底层的Logger是可以切换的,你可以选择log4j,java.util.logging或者它自带的Simple Logger。不过我仍然强烈建议使用log4j,因为log4j性能很高,log输出信息时间几乎等于System.out,而处理一条log平均只需要5us。你可以在Hibernate的src目录下找到Hibernate已经为你准备好了的log4j的配置文件,你只需要到Apache 网站去下载log4j就可以了。commons-logging.jar也是必须的jar包。 
    使用Hibernate必须的jar包就是以上的这几个,剩下的都是可选的。 
    · ant.jar: 
    Ant编译工具的jar包,用来编译Hibernate源代码的。如果你不准备修改和编译Hibernate源代码,那么就没有什么用,可选的jar包 
    · optional.jar: 
    Ant的一个辅助包。 
    · c3p0.jar: 
    C3PO是一个数据库连接池,Hibernate可以配置为使用C3PO连接池。如果你准备用这个连接池,就需要这个jar包。 
    · proxool.jar: 
    也是一个连接池,同上。 
    · commons-pool.jar, commons-dbcp.jar: 
    DBCP数据库连接池,Apache的Jakarta组织开发的,Tomcat4的连接池也是DBCP。 
    实际上Hibernate自己也实现了一个非常非常简单的数据库连接池,加上上面3个,你实际上可以在Hibernate上选择4种不同的数据库连接池,选择哪一个看个人的偏好,不过DBCP可能更通用一些。另外强调一点,如果在EJB中使用Hibernate,一定要用App Server的连接池,不要用以上4种连接池,否则容器管理事务不起作用。 
    · connector.jar: 
    JCA 规范,如果你在App Server上把Hibernate配置为Connector的话,就需要这个jar。不过实际上一般App Server肯定会带上这个包,所以实际上是多余的包。 
    · jaas.jar: 
    JAAS是用来进行权限验证的,已经包含在JDK1.4里面了。所以实际上是多余的包。 
    · jcs.jar: 
    如果你准备在Hibernate中使用JCS的话,那么必须包括它,否则就不用。 
    · jdbc2_0-stdext.jar: 
    JDBC2.0的扩展包,一般来说数据库连接池会用上它。不过App Server都会带上,所以也是多余的。 
    · jta.jar: 
    JTA规范,当Hibernate使用JTA的时候需要,不过App Server都会带上,所以也是多余的。 
    · junit.jar: 
    Junit包,当你运行Hibernate自带的测试代码的时候需要,否则就不用。 
    · xalan.jar, xerces.jar, xml-apis.jar: 
    Xerces是XML解析器,Xalan是格式化器,xml-apis实际上是JAXP。一般App Server都会带上,JDK1.4也包含了解析器,不过不是Xerces,是Crimson,效率比较差,不过Hibernate用XML只不过是读取配置文件,性能没什么紧要的,所以也是多余的。
      

  3.   

    Hibernate是对JDBC的轻量级对象封装,Hibernate本身是不具备Transaction处理功能的,Hibernate的Transaction实际上是底层的JDBC Transaction的封装,或者是JTA Transaction的封装,下面我们详细的分析:
    Hibernate可以配置为JDBCTransaction或者是JTATransaction,这取决于你在hibernate.properties中的配置:
    #hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
    #hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory
    如果你什么都不配置,默认情况下使用JDBCTransaction,如果你配置为:
    hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
    将使用JTATransaction
    不管你准备让Hibernate使用JDBCTransaction,还是JTATransaction,我的忠告就是什么都不配,将让它保持默认状态,如下:
    #hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
    #hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory
    在下面的分析中我会给出原因。
    一、JDBC Transaction
    看看使用JDBC Transaction的时候我们的代码例子:
    Session session = sf.openSession();
    Transaction tx = session.beginTransactioin();
    ...
    session.flush();
    tx.commit();
    session.close();
    这是默认的情况,当你在代码中使用Hibernate的Transaction的时候实际上就是JDBCTransaction。那么JDBCTransaction究竟是什么东西呢?来看看源代码就清楚了:
    Hibernate2.0.3源代码中的类
    net.sf.hibernate.transaction.JDBCTransaction:public void begin() throws HibernateException {
        
    ...
            if (toggleAutoCommit) session.connection().setAutoCommit(false);
    ...
    }
    这是启动Transaction的方法,看到 connection().setAutoCommit(false) 了吗?是不是很熟悉?
    再来看
    public void commit() throws HibernateException {    
    ...
        try {
            if ( session.getFlushMode()!=FlushMode.NEVER ) session.flush();
            try {
                session.connection().commit();
                committed = true;
            }
    ...
        toggleAutoCommit();
    }
    这是提交方法,看到connection().commit() 了吗?下面就不用我多说了,这个类代码非常简单易懂,通过阅读使我们明白Hibernate的Transaction都在干了些什么?我现在把用Hibernate写的例子翻译成JDBC,大家就一目了然了:
    Connection conn = ...;         <---   session = sf.openSession();conn.setAutoCommit(false);     <---   tx = session.beginTransactioin();...                            <---   ...conn.commit();                 <---   tx.commit(); (对应左边的两句)
    conn.setAutoCommit(true);conn.close();                  <---   session.close();
    看明白了吧,Hibernate的JDBCTransaction根本就是conn.commit而已,根本毫无神秘可言,只不过在Hibernate中,Session打开的时候,就会自动conn.setAutoCommit(false),不像一般的JDBC,默认都是true,所以你最后不写commit也没有关系,由于Hibernate已经把AutoCommit给关掉了,所以用Hibernate的时候,你在程序中不写Transaction的话,数据库根本就没有反应。
    二、JTATransaction
    如果你在EJB中使用Hibernate,或者准备用JTA来管理跨Session的长事务,那么就需要使用JTATransaction,先看一个例子:
    javax.transaction.UserTransaction tx = new InitialContext().lookup("javax.transaction.UserTransaction");Session s1 = sf.openSession();
    ...
    s1.flush();
    s1.close();...Session s2 = sf.openSession();
    ...
    s2.flush();
    s2.close();tx.commit();
    这是标准的使用JTA的代码片断,Transaction是跨Session的,它的生命周期比Session要长。如果你在EJB中使用Hibernate,那么是最简单不过的了,你什么Transaction代码统统都不要写了,直接在EJB的部署描述符上配置某某方法是否使用事务就可以了。
    现在我们来分析一下JTATransaction的源代码, net.sf.hibernate.transaction.JTATransaction:
    public void begin(InitialContext context, ...
      ...
      ut = (UserTransaction) context.lookup(utName);
      ...
    看清楚了吗? 和我上面写的代码 tx = new Initial Context?().lookup("javax.transaction.UserTransaction"); 是不是完全一样?
    public void commit() ...
      ...
      if (newTransaction) ut.commit();
      ...
    JTATransaction的控制稍微复杂,不过仍然可以很清楚的看出来Hibernate是如何封装JTA的Transaction代码的。
    但是你现在是否看到了什么问题? 仔细想一下,Hibernate Transaction是从Session中获得的,tx = session.beginTransaction(),最后要先提交tx,然后再session.close,这完全符合JDBC的Transaction的操作顺序,但是这个顺序是和JTA的Transactioin操作顺序彻底矛盾的!!! JTA是先启动Transaction,然后启动Session,关闭Session,最后提交Transaction,因此当你使用JTA的Transaction的时候,那么就千万不要使用Hibernate的Transaction,而是应该像我上面的JTA的代码片断那样使用才行。
    总结:
    1、在JDBC上使用Hibernate
    必须写上Hibernate Transaction代码,否则数据库没有反应。此时Hibernate的Transaction就是Connection.commit而已
    2、在JTA上使用Hibernate
    写JTA的Transaction代码,不要写Hibernate的Transaction代码,否则程序会报错
    3、在EJB上使用Hibernate
    什么Transactioin代码都不要写,在EJB的部署描述符里面配置
    |---CMT(Container Managed Transaction)
    |
    |---BMT(Bean Managed Transaction)
            |
            |----JDBC Transaction
            |
            |----JTA Transaction
     
    提问: 
    javax.transaction.UserTransaction tx = new InitialContext().lookup("javax.transaction.UserTransaction"); Session s1 = sf.openSession(); 
      

  4.   

    ... 
    s1.flush(); 
    s1.close(); ... Session s2 = sf.openSession(); 
    ... 
    s2.flush(); 
    s2.close(); tx.commit();
    s1不关闭,使用s2进行操作的代码中使用s1可不可以(我觉得这样更加节约资源,不需要反复的连接、关闭)
    但sf.opengSession()时,并没有setAutoCommit(false),我想问的是,如果不编写任何事务代码,如: 
    Session s = sf.openSession(); 
    ...... 
    s.close(); 
    数据库会不会有反应(此时应该是默认AutoCommit为true)。
    不会有反应。在sf.openSession() 创建Session实例的时候,就已经调用了conn.setAutoCommit(false)了。
    另外,我想问一下:
    <code> 
    1. s.flush()是不是必须的 
    2. s.close()是不是一定要关闭 
    </code>
     
    回答:
    s.flush不是必须的,s.close()会调用一次s.flush()
    s.close()正常情况下应该关闭,除非你是用ThreadLocal管理Session。
    s1不关闭,使用s2进行操作的代码中使用s1可不可以(我觉得这样更加节约资源,不需要反复的连接、关闭)</code>在这个例子中看不出来JTA的作用。
    假设
    <code>Class A  {
      find() {
        Session s1 = sf.openSession(); 
        ... 
        s1.flush(); 
        s1.close(); 
      }
    }</code><code>Class B  {
      find() {
        Session s2 = sf.openSession(); 
        ... 
        s2.flush(); 
        s2.close(); 
      }
    }
    Main {  tx = ...;
      A.find();
      B.find();
      tx.commit();
    }
    看明白了吗?JTA的Transaction管理是跨类调用的。