• 博客访问: 2240113
  • 博文数量: 422
  • 用 户 组: 普通用户
  • 注册时间: 2009-07-04 10:12
  • 认证徽章:
个人简介

ORACLE ACE-A,自07年接触ORACLE数据库,拥有7年ORACLE数据库运维经验,ACOUG,SHOUG核心成员,曾先后就职于东软集团股份有限公司、阿里巴巴(中国)网络科技有限公司,现就职于无锡新彩软件有限公司担任数据库架构师、DBA主管,负责公司数据库架构的设计、DB的规模化运维和性能调优。

文章分类

全部博文(422)

分类: Oracle

2018-04-25 14:09:10

1. 脏读、不可重复读、幻读,是一种缺陷
2. 隔离级别越高,能解决的“缺陷”越多,为什么不直接使用最高的事务隔离级别,那不就没有缺陷了?
因为传统的以锁的方式去实现的隔离级别,级别越高,并发性越低。
3. 脏读,解决 写不阻塞读 的问题,提高并发现,牺牲一致性。现在绝大多数的主流数据库,都是通过MVCC来解决写不阻塞读的问题,而不是通过锁来实现
4. 为什么会出现不可重复读取?
因为对于读取过的数据并不加锁(读取的当时加共享锁,读取完成后释放共享锁),所以第二次读的时候数据可能已经被其他事务修改而发生了变化
5. 如何才能做到可重复读?
老一辈的数据库艺术家用的方式是加锁,对读取过的数据加锁,就能保证每一次读取到的数据都是一样的,因为对读取过的数据加锁后,数据就无法修改了。这也是repeatable read这个隔离级别要解决的问题,但是标准的可重复读会产生幻读。但现在绝大多数的主流数据库,是通过MVCC来做到的可重复读,而不是通过加锁。
6. 经典的可重复读提供了一个一致性(语句级和事务级)的读取方式,虽存在幻读,单从一致性的角度看,并不是一个大的缺陷,如果以经典的锁的方式去实现可重复读,发生死锁的概率极大,但带来的一个副作用,解决了丢失更新的问题。
7. 从一致性读的角度去看隔离级别,read uncommited,read commited,都不能提供一致性读。强调一遍,我这里说的是,经典的隔离级别,而不是指具体的某个数据库。例如MySQL和Oracle都通过MVCC实现了在read commited级别下的语句级的一致性。经典的隔离级别下,repeatable read在语句级一致性的基础上实现了事务级的一致性。
8.针对oracle的隔离级别来说,read commited级别能够提供语句级一致性的数据(虽没有语句级幻读的概念,这里发明创造一下,它也解决了语句级幻读的问题),这个隔离级别避免不了事务级的幻读的问题,需要read only或者最高的SERIALIZABLE级别。
9.在一个采用共享读锁(而不是多版本)的数据库中,如果启用了REPEATABLE READ,不会发生丢失更新。原因是:已被读取的数据会在上面加一个锁,这个锁会保证数据不能被任何其他事务修改。
10. 在可重复读(REPEATABLE READ,简称RR)隔离级别下,read view是在第一个读请求发起时创建的。在读已提交(READ COMMITTED,简称RC)隔离级别下,则是在每次读请求时都会重新创建一份ead view。根据上面提到的说法,RC隔离级别下,是每次发起SELECT都会创建read view,也就是每次SELECT都能读取到本次查询开始时的已经COMMIT的数据,所以才会出现不可重复读、幻读现象。
11. read view 判断当前版本数据项是否可见
在innodb中,创建一个新事务的时候,innodb会将当前系统中的活跃事务列表(trx_sys->trx_list)创建一个副本(read view),副本中保存的是系统当前不应该被本事务看到的其他事务id列表。当用户在这个事务中要读取该行记录的时候,innodb会将该行当前的版本号与该read view进行比较。

具体的算法如下:
1. 设该行的当前事务id为trx_id_0,read view中最早的事务id为trx_id_1, 最迟的事务id为trx_id_2.
2. 如果trx_id_0< trx_id_1的话,那么表明该行记录所在的事务已经在本次新事务创建之前就提交了,所以该行记录的当前值是可见的。跳到步骤6.
3. 如果trx_id_0>trx_id_2的话,那么表明该行记录所在的事务在本次新事务创建之后才开启,所以该行记录的当前值不可见.跳到步骤5。
4. 如果trx_id_1<=trx_id_0<=trx_id_2, 那么表明该行记录所在事务在本次新事务创建的时候处于活动状态,从trx_id_1到trx_id_2进行遍历,如果trx_id_0等于他们之中的某个事务id的话,那么不可见。跳到步骤5.
5. 从该行记录的DB_ROLL_PTR指针所指向的回滚段中取出最新的undo-log的版本号,将它赋值该trx_id_0,然后跳到步骤2.
6. 将该可见行的值返回。

需要注意的是,新建事务(当前事务)与正在内存中commit 的事务不在活跃事务链表中。

阅读(3175) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册