hibernate的事务管理
一、数据库事务
1. 概念:
数据库事务指把一系列数据库操作组成一个单元,要么全部取消,要么全部完成。即提交和回滚操作。
2. 特性:
(1) 原子性
表示组成一个事务的多个数据库操作是一个不可分隔的原子单元,只有所有的操作执行成功,整个事务才提交,事务中任何一个数据库操作失败,已经执行的任何操作都必须撤销,让数据库返回到初始状态;
(2) 一致性
事务执行前后必须在逻辑上一致,即数据不会被破坏。如从A账户转账100元到B账户,不管操作成功与否,A和B的存款总额是不变的;
(3) 隔离性
在并发数据操作时,不同的事务拥有各自数据空间,彼此之间相互隔离,隔离级别可以设置。
(4) 持久性
对数据库的修改都要写入硬盘中,若在操作过程中发生断电或系统错误,数据库要保证未提交的事务在下次启动之前要撤销,结束的事务要把修改结果写入硬盘。
3. 事务的使用分类
(1) 编程式事务
直接使用JDBC、JTA或者相关框架的API以编写代码的方式设置事务的边界和隔离级别。(JDBC中的事务是自动提交的,可以通过Connection对象的setAutoCommit(false)方法取消自动提交。
(2) 声明式事务
依赖应用服务器提供的服务(weblogic server)或者相关框架的API(spring framework)在配置文件中设置相关信息。
4. 并发访问数据库可能引发的问题
(1) 脏读
A事务读取B事务尚未提交的更改数据,并在这个数据的基础上操作。即恰巧读取了B事务回滚之前的数据。
(2) 不可重复读
A事务读取了B事务已经提交的更改数据(更新和删除),导致数据处理上的混乱。即A事务两次读取期间,B事务进行了更新或删除操作。
为防止,只需要对操作的数据添加行级锁,阻止操作中的数据发生变化。
(3) 幻读
A事务读取B事务提交的新增数据(插入),这时A事务将出现幻象读的问题。幻象读一般发生在计算统计数据的事务中。
为防止,需要添加表级锁,将整个表锁定,防止新增数据。
(4)第一类丢失更新
A事务撤销时,把已经提交的B事务的更新数据覆盖了。若数据库没有隔离事务就会发生该现象。
(5) 第二类丢失更新
A事务提交时,覆盖了B事务已经提交的数据,造成B事务所做操作丢失。
5. 事务隔离级别:
隔离性是通过数据库的表或字段加锁实现的。事务隔离级别分为以下四种:
(1) Read Uncommitted 读未提交
一个事务可以读取另一个事务已更新但未提交的数据,但另一事务提交前不允许写入。
(2) Read committed 读提交(oracle默认事务)
一个事务仅可以读取另一个事务已提交的更新数据。
(3) Repeatable read 重复读
一个事务已读取的数据不允许其他事务的写入。
(4)Serializable 序列化
所以事务序列化进行,不能并发执行。
√: 可能出现 ×: 不会出现
隔离级别 | 更新丢失 | 脏读 | 不可重复读 | 幻读 |
Read uncommitted | × | √ | √ | √ |
Read committed | × | × | √ | √ |
Repeatable read | × | × | × | √ |
Serializable | × | × | × | × |
二、hibernate中的事务
hibernate是对JDBC的封装,本身并不具备事务处理能力,他将事务处理交给底层的JDBC或者JTA处理。
1. 锁
在hibernate中不仅可以通过宏观角度设置数据库的不同事务隔离级别,还可以从微观角度使用乐观锁和悲观锁进一步控制并发事务。(例如在结算时不允许数据发生变化可以对该数据加锁)
2. Hibernate的锁定模式
Hibernate可以自动设置锁定模式,还可以调用Session对象的load()和lock()方法,Query或Criteria对象的setLockMode()方法显式设置并使用下述模式。
(1)LockMode.NONE
如果在Hibernate的缓存中存在指定对象,就直接返回该对象的引用;否则就通过Select语句到数据库中加载该对象。这是默认值
(2)LockMode.Read
不管Hibernate的缓存中是否存在指定对象,总是通过select语句到数据库中加载该对象。
(3)LockMode.UPGRADE
不管Hibernate的缓存中是否存在指定对象,总是通过select语句到数据库中加载该对象;如果数据库系统支持悲观锁就执行select ... for update语句,如果数据库系统不支持悲观锁,就执行普通的select语句。
(4)LockMode.UPGRADE_NOWAIT
和LockMode.UPGRADE具有同样的功能。此外对于Oracle数据库,执行select ... for update nowait语句
(5)LockMode.WRITE
当Hibernate向数据库插入或者更新一个对象时,会自动使用此模式。Hibernate会在写入数据时自动使用该模式。
3. 悲观锁
悲观的认为每次读取或者修改数据库数据时,其他事务也在访问。所以悲观锁会对读取的数据进行锁定,其他事务不能访问。
使用方法:
Query的setLockMode()方法:query.setLockMode(“book”,LockMode.UPGRADE);
Session的lock()方法: session.lock(book, LockMode.UPGRADE);
4. 乐观锁
(1)乐观锁定采用的版本策略有:先提交为主(First commit win)、后提交为主(Last commit win)、合并冲突更新(Merge cofilcting updates)。
(2)Hibernate推荐采用“版本号来实现先提交为主”的乐观锁定模式。在数据库中增加一列version,每次读取时,连该列一起读取,在更新的时候将此版本号和数据库中的版本号进行比较,如果大于等于则可以更新,如果小于则抛出异常。其是在配置文件中设置的。
(3)也可以采用时间戳实现乐观锁,比较时间戳大小。
注:本文参考《Hibernate开发与实战》 刘伟 张利国 电子工业出版社 一书
本文出自 “java我的最爱” 博客,请务必保留此出处http://lindianli.blog.51cto.com/7129432/1433111
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。