Hibernate_8

Hibernate可以与任何一种Java应用的运行环境集成。Java应用的运行环境可分为两种:
受管理环境(Managed environment):由容器负责管理各种共享资源(线程池和数据库连接池等),支持CMT(Container Managered Transaction,完全由容器管理事务)事务模式等。
不受管理环境(Non-managed environment):由应用本身负责管理数据库连接、定义事务边界及管理安全,独立的桌面应用或命令行应用都运行在不受管理环境中。Servlet容器会负责管理线程池,但Servlet容器不支持CMT事务模式,因此它提供的仍然是不受管理的运行环境。

数据库连接池的基本实现原理是:事先建立一定数量的数据库连接,这些连接存放在连接池中,当java应用执行一个数据库事务时,只需从连接池中取出空闲状态的数据库连接;当java应用执行完事务,再将数据库连接放回连接池。

对于使用Hibernate的Java应用,构造及访问连接池的任务通常由Hibernate完成。
在受管理环境中,容器负责构造连接池的实例,Java应用直接访问容器提供的连接池实例。不同的连接池有不同的API,若Java应用直接访问连接池的API,会削弱Java应用与连接池之间的独立性。为提高Java应用与连接池之间的独立性,SUN公司指定了标准的javax.sql.DataSource接口,用于封装各种不同的连接池实现。对于每一种实现javax.sql.DataSource接口的连接池,都会提供负责构造DataSource实例的工厂类。在受管理环境中,容器通过这个工厂类构造出DataSource实例,然后把它发布为JNDI(Java Naming and Directory Interface)资源,允许java应用通过JNDI API来访问它。
可以简单地把JNDI理解为一种将对象和名字绑定的技术,对象工厂负责生产出对象,这些对象都和唯一的JNDI名字绑定,外部程序通过JNDI名字获得某个对象的引用。

Hibernate有3种方式获得数据库连接池:使用默认的数据库连接池、使用配置文件指定的数据库连接池、在受管理环境中,从容其中获得标准的数据源。
Hibernate把不同来源的连接池抽象为org.hibernate.connection.ConnectionProvider接口,Hibernate提供了以下内置的ConnectionProvoder实现类。
DriverManagerConnectionProvider:代表由Hibernate提供的默认的数据库连接池 C3P0Connection:代表C3P0连接池
ProxoolConnectionProvider:代表Proxool连接池
DataSourceConnectionProvider:代表在受管理环境中由容器提供的数据源

Hibernate还允许用户扩展ConnectionProvider接口,创建客户化ConnectionProvider实现类。在Hibernate配置文件中,hibernate.connection.provider_class属性用来指定ConnectionProvider实现类。Hibernate的ConnectionProviderFactory工厂类根据provider_class属性来构造相应的ConnectionProvider实例。若用户使用的是Hibernate的内置ConnectionProvider实现类,也可不设置provider_class属性。

使用C3P0连接池的hibernate.properties文件
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=jdbc:mysql://localhost:3306/DBName
hibernate.connection.username=forever
hibernate.connection.password=forever
hibernate.show_sql=true
hibernate.c3p0.min_size=5     //在连接池中可用的数据库的最少数目
hibernate.c3p0.max_size=20    //在连接池中所有数据库连接的最大数目
hibernate.c3p0.timeout=300    //设定数据库连接的过期时间,以秒为单位
hibernate.c3p0.max_statements=50  //可以被缓存的PreparedStatement实例的最大数目
hibernate.c3p0.idle_test_period=300  //在使数据库连接自动生效之前处于空闲状态的时间,以秒为单位

在受管理环境中,容器负责构造数据源,即javax.sql.DataSource的实例,然后把它发布为JNDI资源,Hibernate的DataSourceConnectionProvider类充当这个数据源的代理。在不受管理环境中,有些Servlet容器,如Tomcat,也可负责构造数据源,并能把它发布为JNDI资源。

以Tomcat为例,为了使Hibernate从容器中获得数据源,需要分别设置Tomcat容器和Hibernate:
在Tomcat容器中配置数据源;在Hibernate的配置文件中指定使用个容器中的数据源。
在Tomcat容器中配置数据源:
在Tomcat的配置问价server.xml中,<Resource>元素用来匹配JNDI资源,Tomcat允许把数据源也发布为JNDI资源
<Resource
    name="jdbc/SAMPLEDB"  //指定Resource的JNDI名字
    auth="Container"  //指定Resoucre的Manager:Container(容器)和Application(Web应用)
    type="javax.sql.DataSource" //指定Resource所述的Java类名
    maxActive="100" //指定数据库连接池中处于活动状态的数据库连接的最大数目
    maxIdle="30"  //指定数据库连接池中处于空闲状态的数据库连接的最大数目
    maxWait="10000" //指定数据库连接池中的数据库链接处于空闲状态的最长时间
    username="root" 
    password="tiger"
    driverClassName="com.muysql.jdbc.Driver"
    url="jdbc:mysql://localhost:3306/SAMPLEDB?autoReconnect=true"    
/>
在Hibernate配置文件中指定使用容器中的数据源
在Hibernate的配置文件中,hibernate.connection.datasoure属性用于指定容器中的数据源。
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.connection.dtasource=java:comp/env/jdbc/SAMPLEDB
hibernate.show_sql=true

当Java应用通过Hibernate访问数据库时,先调用SessionFactory的openSession()方法获得一个Session实例,然后通过Session实例执行具体的数据库操作。对于每一个Session实例,Hibernate都会为它分配数据库连接。在默认的情况下,Hibernate从数据库连接池中获得可用的数据库连接。此外,Hibernate还允许由应用程序为ession指定数据库连接。SessionFactory的openSession()方法有以下几种重载方式:
openSession():由Hibernate从数据库连接池中获得可用的数据库连接
openSession(Connection connection):由应用程序提供数据库连接

在Java应用中,按照声明事务边界的接口划分,事务可分为两类:
JDBC事务:依赖于JDBC API来声明事务边界,适用于任何Java环境
JTA事务,依赖于JTA来声明事务边界,适用于基于J2EE的受管理环境,以及支持JTA的不受管理环境。
JTA(Java Transaction API)是SUN公司为就JavaEE的受管理环境制定的标准事务API。此外,有些JTA实现可以脱离容器独立运行,因此在不受管理环境中,Java应用过可访问基于这种实现的JTA。JTA支持分布式的事务及扩数据库平台的事务。JTA中的两个核心接口为:
TransactionManager:事务管理器,参与管理事务的生命周期
UserTransaction:Java应用通过这个接口来声明事务边界
在受管理环境中,JTA事务分为CMT(Container Managered Transaction,完全由容器管理事务)和BMT(Bean Managered Transaction,由Bean来管理自己的事务)两种模式。在CMT事务模式下,应用不必再程序代码中声明事务边界,而只需在部署文件中配置事务,然后由容器通过TransactionManager来管理事务。在BMT事务模式下,应用在程序代码中通过UserTransaction接口来声明事务边界。

对于使用Hibernate的Java应用,Java应用声明事务有两种方式:
直接通过JTA API来声明JTA事务。
通过Hibernate API来声明事务。

Hibernate把不同类型的事务抽象为org.hibenate.Transaction接口,并提供了两个内置的实现类:JDBCTransaction(代表JDBC事务)、JTATransaction(代表JTA事务)。
Hibernate通过以下事务工厂类来狗仔JDBC或JTA事务实例:
JDBCTransactionFactory:负责构造JDBCTransaction实例
JTATransactionFactory:负责构造JTATransaction实例
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.connection.datasource=java:comp/env/jdbc/SAMPLEDB
hibernate.transaction.factory_class=org.hibernate.transaction.JTATransactionFactory
//指定TransactionManagerLookUp接口的实现类,负责定位容器中JTATransactionManager
hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JBossTransactionManagerLookip
hibernate.show_sql=true
只有当毒药使Hibernate的第二级缓存,或使用了hilo标识符生成策略,或由容器来管理事务时,才必须设置manager_lookup_class属性,在其他情况下,可以不设置manager_lookup_class属性。

若应用程序仅在不受管理环境中运行,可以采用默认的JDBC事务,应用程序通过Hibernate API来声明事务边界,在配置文件中采用默认的JDBCTransactionFactory事务工厂。若应用程序仅在受管理环境中运行,应该优先考虑采用JTA事务,应用程序通过JTA API来声明事务边界,在配置文件中配置JTATransactionFactory事务工厂。

如何配置事务?
为了保证应用程序代码的独立性,以及在各种运行环境下具有相同的运行时行为,优先考虑在程序中通过JTA API来声明事务。应用发布者负责配置不受管理或受管理环境中JTA实现的提供者。此外,事务的集成及资源的管理也由应用发布者,而不是应用程序来负责。在Hibernate配置文件中应该配置JTATransactionFactory事务工厂,此外,还要配置相应的TransactionManagerLookup。
其次,对于EJB组件,可以采用CMT事务模式。
最后,在万不得已的情况下,如必须保证声明事务的程序代码的兼容性,并且在不受管理环境下不支持JTA,可以考虑在程序中通过Hibernate API来声明事务。此时Hibernate API根据在各个环境下配置的特定事务工厂(JDBCTransactionFactory或JTATransactionFactory),自动切换到JDBC事务或JTA事务。

在不同的运行环境中,SessionFactory有不同的存取方案:
创建一个实用类:HibernateUtil,在这个类中定义static类型的SessionFactory变量,以及public static 类型的getSessionFactory()方法
在Servlet容器中,把SessionFactory实例存放在javax.servlet.ServletContext中,即JavaWeb应用范围内。
在基于JavaEE的受管理环境中,把SessionFactory发布为JNDI资源。

在Hibernate的配置文件中,hibernate.session_factory_name属性指定SessionFactory的JNDI名字,若受管理环境中设置了这个属性,Hibernate就会把SessionFactory发布为JNDI资源
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.connection.datasource=java:copm/env/jdbc/SAMPLEDB
hibernate.transaction.factory_Class=org.hibernate.transaction.JTATransactionFactory
hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JTATransactionManagerLookup
hibernate.session_factory_name=java:hibernate/HibernateFactory
hibernate.show_sql=true
Context ctx = new InitialContext();
String jndiName="java:hibernate/HibernateFactory";
SessionFactory sessionFactory = (SessionFactory)ctx.lookup(jndiName);
Session session = sessionFactory.openSession();
...

Hibernate采用SLF4J(Simple Logging Facade for Java)日志工具来记录各种各样的系统事件。SLF4J把日志由低到高分为5个级别:DEBUG、INFO、WARN、ERROR和FATAL。
SLF4J对目前常见的一些日志工具提供了适配器,对这些日志工具提供了服务进行了抽象,为客户程序提供了统一的输出日志的API:
NOP:什么也不做,不输出任何日志
Simple:SLF4J自带的简单的日志工具实现,通过System.err来输出日志,仅输出INFO级别或更高级别的日志
Log4J:允许指定日志信息输出的目的地,还可以控制每一条日志的输出格式,此外,通过定义日志信息的级别,Log4J能非常细致地控制日志的输出与否。可以通过log4j.properties配置
JDK1.4Log:JDK1.4及以上版本中自带的日志工具
JCL(Jakarta Commons Logging):提供了通用的输出日志的API

log4j.properties
#指定根日志器的输出目的地,输出日志级别
log4j.rotLogger=WARM, A1,A2

#A1为控制台
log4j.appender.A1=org.apache.log4j.ConsoleAppender

#指定向A1控制台输出的日志的格式
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%p [%t] %c{2} {%m:%L} - %m%n

#A2为C:/log.txt文件
log4j.appender.A2=org.apache.log4j.FileAppender
log4j.appender.A2.File=C:/log.txt

#指定向A2控制台输出的日志的格式
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.ConversionPattern=%5r %-5p [%t] $c{2} -%m%n

log4j.logger.org.hibernate=INFO
log4j.logger.org.hibernate.hql.ast.AST=DEBUG
log4j.logger.org.hibernate.SQL=DEBUG
log4j.logger.org.hibernate.tool.hbm2ddl=DEBUG
log4j.logger.org.hibernate.hql=DEBUG

你可能感兴趣的:(Hibernate,数据库连接池)