标签:
事务由那几个特性,四个(ACID):1.原子性(要么全部完成,要么全部不完成);2.一致性(事务开始之前和事务结束以后,数据库的完整性约束没有被破坏);3.隔离性(两个事务的执行是互不干扰的);4.持久性(Durability)
事务并发是不可避免的,从而会出现以下几个问题: 1.丢失更新(Lost Update)(第一类即回滚覆盖和第二类即提交覆盖);2.脏读(读取未提交数据); 3.不可重复读(两次读取中有其他事务对数据值进行更新); 4.幻读(两次读取中其他事务添加或删除记录)
针对并发事务出现的问题,Hibernate 采用了数据库的事务隔离机制(详细文档见Herbernate 参考文档的 java.sql.Connection ),一般有以下四种处理机制:
1.read-uncommitted
2.read-committed
3.repeatable read
4.serializable
A. 只要数据库支持事务,就不可能出现第一类丢失更新
B. read-uncommitted(允许读取未提交的数据)会出现dirty read , 幻读phantom-read,non-repeatable read 问题
C. read-committed(读取已提交的数据 ,项目中一般使用这个,MySql 数据库默认是这种机制)不会出现dirty read ,因为只有另一个事务提交才会读出来结果,但仍然会出现non-repeatable和phantom-read
(所以使用read-committed 机制可用悲观锁和乐观锁来解决non-repeatable 和 phantom-read 问题)
在hibernate中的事务隔离级别的设定(使用 hibernate.connection.isolation配置,取之1,2,4,8)
1.hibernate.connection.isolation = 2 (如果不设置,默认依赖数据库本身的级别,例如MySql为2,read-committed)
2.使用悲观锁解决repeatable read 的问题(依赖于数据库的锁)
a. 使用悲观锁查找数据或者更新数据时,默认加上for update ,表示对当前事务加锁,其他事务暂时不能使用,例如 select ... for update
b. 在程序中如何加上悲观锁呢,很简单,直接在session的load方法中添加一个参数即可,例如:
Account a = (Account)session.load(Account.class, 1, LockMode.UPGRADE);
锁的模式:
a.LockMode.None 无锁的机制,Transaction 介绍时,切换到此模式
b.LockMode.read 在查询的时候hibernate会自动获取锁
c.LockMode.write insert update hibernate会自动获取锁
以上3种锁的模式,是hibernate内部使用的(不需要设置)
d.LockMode.UPGRADE_NOWAIT 是Oracle 支持的索的模式
3.使用乐观锁解决repeatable read 的问题
直接在实体类中添加 version 属性
D. repeatable read (事务执行中其他事务无法执行修改或插入操作 较安全)
E. serializable 解决事务隔离级别(顺序执行事务,不并发,实际当中很少使用)
悲观锁
在应用程序中显示地为数据资源加锁.悲观锁假定当前事务操纵数据资源时,肯定还会有其它事务同时访问该数据资源,为了避免当前事务的操作受到干扰,先锁定资源.尽管悲观锁能防止丢失更新和不可重复读这类并发问题,但会影响并发性能.(简单理解,就是每次在操作数据时总是悲观地认为会有别的事务也会来操纵同一数据,从此锁住该笔数据,直到自己操作完成后再解除锁)
假定当前事务操纵数据资源时,不会有其它事务同时访问该数据资源,因此完全依靠数据库的隔离级别来自动管理锁的工作.应用程序采用版本控制手段来避免可能出现的并发问题.(所谓乐观锁,它通常认为多个事务同时操纵同一数据的情况是很少的,因为根本不做数据库层次上的锁定,只是基于数据的版本标识实现应用程序级别上的锁定机制,既保证了多个事务的并发访问,又有效地防止了第二类丢失更新的出现)
l 加锁条件:当一个事务执行select语句时,数据库系统会为这个事务分配一把共享锁,锁定被查询的数据.
l 解锁条件:数据被读取后,数据库系统立即解除共享锁.
l 与其它锁的兼容性:如果数据资源上放置了共享锁,还能再放置共享锁和更新锁.
l 并发性能:良好的并发性能.当多个事务读相同数据时,每个事务都会获得一把共享锁,可以同时读锁定的数据.
l 加锁条件:当一个事务执行insert,update,delete时,数据库系统会自动对SQL语句操纵的数据资源使用独占锁.如果该数据资源已经有其它锁存在时,无法对其再放置独占锁.
l 解锁条件:独占锁一直到事务结束后才能被解除.
l 与其它锁的兼容性:独占锁不能和其他锁兼容,如果数据资源已经加上了独占锁, 就不能再放置其它锁,同样,如果已经有了其它锁,就不能放置独占锁.
l 并发性能:并发性能较差,只允许有一个事务访问锁定的数据,如果其他事务也需要访问该数据,就必须等待,直到前一个事务结束,解除了独占锁,其它事务才能访问该数据.
l 加锁条件:当一个事务进行update操作时,数据库系统会先为事务分配一把更新锁.
l 解锁条件:当读取数据完毕,执行更新操作时,会把更新锁升级为独占锁.
l 与其它锁的兼容性:更新锁与共享锁兼容,即一个资源可以同时放置更新锁和共享锁,但是最多只能放置一把更新锁,这样,当多个事务更新相同的数据时,只有一个事务能获得更新锁,然后再把更新锁升级为独占锁,其它事务必须等到前一个事务结束后,才能获得更新锁,避免了死锁.
l 并发性能:允许多个事务同时读锁定资源,但不允许其它事务修改它.
隔离级别 |
是否出现第一类丢失更新 |
是否出现第二类丢失更新 |
是否出现脏读 |
是否出现幻读 |
是否出现不可重复读 |
Serializable串行化 |
否 |
否 |
否 |
否 |
否 |
RepeatableRead可重复读 |
否 |
否 |
是 |
否 |
否 |
ReadCommited读已提交数据 |
否 |
否 |
是 |
是 |
是 |
ReadUncommited读未提交数据 |
标签:
原文地址:http://www.cnblogs.com/shz365/p/5762180.html