本文主要是介绍Hibernate的事务与C3P0的配置,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
在hibernate开发中配置c3p0 数据库连接池
hibernate框架内部使用默认数据库连接池 DriverManagerConnectionProvider 提供
使用c3p0 修改hibernate 默认的 ConnectionProvider
步骤:
1、 导入jar包 hibernate解压目录/lib/optional/c3p0/c3p0-0.9.1.jar
2、 配置hibernate.cfg.xml
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
3、 配置c3p0 详细参数
#hibernate.c3p0.max_size 2
#hibernate.c3p0.min_size 2
#hibernate.c3p0.timeout 5000
#hibernate.c3p0.max_statements100
#hibernate.c3p0.idle_test_period3000
#hibernate.c3p0.acquire_increment2
#hibernate.c3p0.validatefalse
注:在hibernate解压目录中的project\etc\hibernate.properties文件中有所有可以配置的常量。
数据库并发事务问题
事务的四大特性(ACID):原子性、一致性、隔离性、 持久性
事务隔离性引发问题: 脏读、不可重复读、幻读
* 脏读 : 一个事务读取另一个事务 未提交数据
* 不可重复读: 一个事务 读取另一个事务 已经提交数据(update)
* 幻读 : 一个事务 读取 另一个事务已经提交 插入数据 (insert)
* 丢失更新:两个事务同时修改一条数据,后提交事务覆盖了之前的提交结果。
事务隔离级别可以解决隔离性引发问题:
* READ_UNCOMMITED 会发生所有隔离问题
* READ_COMMITTED 会阻止脏读发生,但是会发生 不可重复读和幻读
* REPEATABLE_READ 会阻止脏读和不可重复读,会发生幻读
* SERIALIZABLE 以串行方式处理事务,同一时间只有一个事物,没有并发,没有隔离问题(效率很低)
Mysql 数据库默认级别REPEATABLE_READ ,Oracle 数据库默认级别 READ_COMMITTED
hibernate提供hibernate.connection.isolation属性,用来修改数据库默认隔离级别,取值 1 2 4 8
1—Read uncommitted isolation
2—Read committed isolation
4—Repeatable read isolation
8—Serializable isolation
* mysql 默认是4 , oracle 默认 2
hibernate.cfg.xml 修改隔离级别
<propertyname="hibernate.connection.isolation">2</property>
解决丢失更新问题: 两种方法(悲观锁和乐观锁)
1) 悲观锁原理:使用数据库底层锁机制,对于要修改的数据,在查询时加锁,此时数据只有加锁的 事务可以修改,而其他事务无法再对数据加锁
数据库锁分为读锁(共享锁)和写锁(排它锁)
对于一个表数据可以加多个共享锁,但是只能加一个排它锁,排它锁和任何锁都是互斥
注:在修改数据时,会自动为数据添加排它锁
通过查询添加共享锁和排他锁
select * from customer lock in share mode ; 添加共享锁
select * from customer for update ; 添加排它锁
hibernate 提供了悲观锁机制:Object get(Class clazz,Serializable id, LockMode lockMode)
例:Customer customer = (Customer) session.get(Customer.class, 2,LockMode.UPGRADE);
说明:LockMode.UPGRADE(排它锁)已过时
悲观锁可以保证同一时间 只有一个人在修改,不会丢失更新 (缺点:效率很低)
2) 乐观锁原理: 为数据添加一列版本字段,每次修改数据后版本+1(当版本不一致无法修改)
优点:不依赖数据库底层锁机制,可以并发修改。乐观锁是现在企业开发中常用的。
方式: hibernate在hbm文件中 通过<version> 配置乐观锁字段
例:在Customer类中添加 ver版本字段
在Customer.hbm.xml 配置版本字段 <versionname="ver"></version>
Session 的管理
hibernate框架提供三种 session 管理方式
第一种 Session 对象的生命周期与本地线程(ThreadLocal )绑定
第二种 Session 对象的生命周期与 JTA 事务绑定(分布式事务<一个事务有多个数据库连接>,必须 使用分布式服务器 JBOSS、WebLogic )
第三中 Hibernate 委托程序管理 Session 对象的生命周期
在web程序中,Session对象生命周期都是与当前线程进行绑定的,只要线程结束了,session就没有了。
之前我们获取session的方式是通过SessionFactory的openSession()方法随机从数据库连接池中获取一个 连接构造Session对象,但是如果想要获取的session与当前线程绑定就要进行以下配置。
1) 配置 hibernate.cfg.xml
<!-- 配置Session 与当前线程 绑定 -->
<property name="hibernate.current_session_context_class">thread</property>
2) 在程序中 通过SessionFactory的getCurrentSession()方法获得Session对象(其实就是从ThreadLocal 中获得一个对象 )
注:当使用SessionFactory 提供 getCurrentSession() 方法时,不用手动的去关闭session,因为当Transaction 提交后,Session 会自动关闭。
session与线程绑定与三层架构
如果简单对web开发分成,可以粗略分为三层:web层、业务层、持久层。对于数据库的操作应该是在持久层,但是问题是在实际开发中的事务管理并不一定在持久层,我们经常在业务层与web层进行控制事务,大多在业务层。由于一次请求应该由服务器进行处理,业务层中有很多业务操作,只要有一个操作失败了,就应该回滚。所以事务应该放到业务层(事务是围绕业务的)。
如果在业务层开启了事务,那么持久层为了保证是在业务层开启的事务中完成的,就需要使用同一个session。所以业务层就要给持久层传递session,这时就要用到threadlocal,将session与线程绑定。
这篇关于Hibernate的事务与C3P0的配置的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!