数据库并发控制

ACID,是指在可靠数据库管理系统(DBMS)中,事务(transaction)所应该具有的四个特性:

A:原子性(Atomicity):事务是一个或多个行为捆绑在一起组成一个单独的工作单元,事务中的动作要不都发生,要不都不发生.

C:一致性(Consistent):即在事务开始之前和结束之后,数据库的完整性约束没有被破坏.

  数据库层面:在一个事务执行前和执行后,数据会符合你设置的约束(例如unique约束,foreign key约束,check约束等)和触发器设置.由数据库进行保证.

  业务层面:保持业务的一致性.需要由开发人员进行保证.

I:隔离性(Isolation):指的是在并发环境中,事务之间互相影响的程度(即并发事务间数据的可见程度).当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间.由并发事务所做的修改必须与任何其他并发事务所做的修改隔离.事务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据. 

D:持久性(Durability):一旦事务完成,事务的结果应该持久化,用来保证即使系统崩溃也不会破坏事务的结果.

 

 

 

 

我们通过可视化界面对不同的数据库进行管理,不可避免要实现多个进程访问数据库同一数据,或者修改同一数据。不得不提到数据库利用加锁和阻塞来保证事物之间不同等级的隔离性,从而实现事务的互不干扰的访问和操作数据库.

干扰数据的隔离性的四大问题:

No.1 丢失修改(丢失更新 ps:反正叫什么的都有)

如果两个事务都要更新数据库一个字段X,X=100;

事务A 事务B
读取X=100  读取X=100
写入x=X+100 写入x=X+200
事务结束x=200  事务结束x=300
  最后x=300

两个不同的事务同时获得了相同的数据,又都对这个数据进行了修改,那么先提交的事务的更新就会被后提交事务的更新覆盖掉.叫做丢失更新.

No.2 脏读(读脏数据 未提交读)

事务A    事务B
  写入x=X+100 (x=200)
读取X=200 (读取了事务B未提交的数据)    
  事务回滚x=100 
  事务结束x=100
事务结束

事务读取了未提交的数据,如图 事务B可能出现未提交或者提交不成功的情况而进行回滚,这就导致事务A读取了错误的数据,也叫脏数据.

No.3 不可重复读

一个事务执行期间,在自己没有更新数据库的情况下,同一个查询操作在执行一次或多次的情况下,结果应该是一致的.

 

事务A 事务B
读取X=100 读取X=100
读取X=100  写入x=X+100
  事务结束, x=200
读取X=200
(此时,在同一个事务A中,读取的X值发生了变化!)
 
事务结束  

这种情况事务A多次读取数据出现不一致的结果.

摘自萨师煊老师的数据库系统概论的解释:不可重复读包括三种情况(这里列举第一种情况 因为后两种情况也称为幻影现象):

(1):事务T1读取某一数据之后,事务T2对其进行了修改,当事务T1再次读该数据时,得到与前一次不同的值.如上所示

No.4 幻读(幻影现象)

这个问题可有意思了,很多博主说他跟不可重复读有相似的地方,我认为这样更容易让读者混淆.数据库书中说的幻影现象就是不可重复读情况中的两种.

(2):事务T1按一定条件从数据库中读取了某些数据记录后,事务T2删除了其中部分记录,当T1再次按照相同条件读取数据时,发现某些记录神秘的消失了.

(3):事务T1按一定条件从数据库中读取了某些数据记录后,事务T2插入了一些记录,当T1再次按照相同条件读取数据时,发现多了一些记录.

知乎大佬的例子:

users: id 主键

1、T1:select * from users where id = 1;

2、T2:insert into `users`(`id`, `name`) values (1, 'big cat');

3、T1:insert into `users`(`id`, `name`) values (1, 'big cat');

 

T1 :主事务,检测表中是否有 id 为 1 的记录,没有则插入,这是我们期望的正常业务逻辑。

T2 :干扰事务,目的在于扰乱 T1 的正常的事务执行。

在 RR(这里摘自知乎某位大佬的回答 我也不晓得RR是什么东东) 隔离级别下,1、2 是会正常执行的,3 则会报错主键冲突,对于 T1 的业务来说是执行失败的,这里 T1 就是发生了幻读,因为T1读取的数据状态并不能支持他的下一步的业务,见鬼了一样。

所以 mysql 的幻读并非什么读取两次返回结果集不同,而是事务在插入事先检测不存在的记录时,惊奇的发现这些数据已经存在了,之前的检测读获取到的数据如同鬼影一般

这里要灵活的理解读取的意思,第一次select是读取,第二次的 insert 其实也属于隐式的读取,只不过是在 mysql 的机制中读取的,插入数据也是要先读取一下有没有主键冲突才能决定是否执行插入。

不可重复读侧重表达 读-读,幻读则是说 读-写,用写来证实读的是鬼影。

作者:知乎用户
链接:https://www.zhihu.com/question/47007926/answer/222348887
来源:知乎
 
大佬的最后一句话:不可重复的侧重表达读-读,幻读则是说读-写.  emmmm....
 
 
在讲隔离级别之前复习一下封锁的知识.
封锁是实现并发控制的一个非常重要的技术.基本的封锁类型有两种:排他锁(X锁)共享锁(S锁);
排它锁又称写锁,若事务T对数据对象A加上X锁,则只允许T读取和修改A,其他任何事务都不能再对A加任何类型的锁直到T释放A上的锁为止.
共享锁又称读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事物只能再对A加S锁,而不能加X锁.
 
 
 
在运用 排他锁 和 共享锁 对数据对象加锁时,还需要约定一些规则,例如何时申请 排他锁 或 共享锁、持锁时间、何时释放等。称这些规则为封锁协议(Locking Protocol)。对封锁方式规定不同的规则,就形成了各种不同的封锁协议。不同的封锁协议对应不同的隔离级别

在标准SQL规范中,定义了4个事务隔离级别,不同的隔离级别对事务的处理不同:

A.  未授权读取(Read uncommited):允许脏读取,但不允许丢失修改。

对应一级封锁协议:一级封锁协议是:事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放。事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK)。 

B.  授权读取(Read Committed):允许不可重复读取,但不允许脏读取和丢失修改。这可以通过“瞬间共享读锁”和“排他写锁”实现。

对应二级封锁协议:二级封锁协议是:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁(瞬间S锁)。

C.  可重复读取(Repeatable Read):禁止不可重复读取和脏读取和丢失修改,但是有时可能出现幻影数据。这可以通过“共享读锁”和“排他写锁”实现。

对应三级封锁协议:三级封锁协议是:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放

D.  序列化(Serializable):提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。

 四级封锁协议是对三级封锁协议的增强,其实现机制也最为简单,直接对事务中所读取或者更改的数据所在的表加表锁,也就是说,其他事务不能读写该表中的任何数据。这样所有的脏读,不可重复读,幻读,都得以避免!

 

我真是日了 好多博客连一级封锁协议都不一样哈 有加排他锁的,有加共享锁的. 我就是按照书上的加排他锁吧.

并发控制有四个问题,也有五个问题的......

我就按照我的这想法吧 毕竟说法那么多 P313附近有这个知识点.有疑问就去查 

 

posted @ 2017-11-08 21:04  谢谢侬  阅读(6544)  评论(0编辑  收藏  举报