欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Hibernate_8 博客分类: Hibenate hibernate数据库连接池配置事务类型 

程序员文章站 2024-03-22 08:14:28
...
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