事务
select * from 表名 where 条件 id > 10
insert into 表名 values()
update 表名 set name = ‘’ where id = 1
delete 表名 where
事务
事务的四大特性(ACID):
原子性(atomicity)
事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位.
一致性(consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
例:拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如同时操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。关于事务的隔离性数据库提供了多种隔离级别
脏读 不可重复读 幻读
1.脏读(Phantom Read):
脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
2.不可重复读(Unrepeatable Read):
是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。(即不能读到相同的数据内容)
例如,一个编辑人员两次读取同一文档,但在两次读取之间,作者重写了该文档。当编辑人员第二次读取文档时,文档已更改。原始读取不可重复。如果只有在作者全部完成编写后编辑人员才可以读取文档,则可以避免该问题。
3.幻读(Dirty Read):
是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
例如,一个编辑人员更改作者提交的文档,但当生产部门将其更改内容合并到该文档的主复本时,发现作者已将未编辑的新材料添加到该文档中。如果在编辑人员和生产部门完成对原始文档的处理之前,任何人都不能将新材料添加到文档中,则可以避免该问题。
不可重复读和幻读很相近。一定需要注意的是,不可重复读强调的是记录的更新(update),幻读强调的是插入和删除(insesrt和delete)
隔离级别
读未提交(read uncommitted)
一个事务还没提交时,它做的变更就能被别的事务看到
读提交(read committed)
一个事务提交之后,它做的变更才会被其他事务看到
可重复读(repeatable read)
一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的
串行化(serializable )
顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行
隔离实现
隔离的实现主要有读写锁和MVCC(Multi-Version Concurrency Control)多版本并发处理方式。
1.读写锁
最简单直接的的事务隔离实现方式,每次读操作需要获取一个共享锁,每次写操作需要获取一个写锁。共享锁之间不会产生互斥,共享锁和写锁之间、以及写锁与写锁之间会产生互斥。当产生锁竞争时,需要等待其中一个操作释放锁后,另一个操作才能获取到锁。
2. MVCC
在读写锁中,读和写的排斥作用大大降低了事务的并发效率,于是人们又提出了能不能让读写之间也不冲突的方法,就是读取数据时通过一种类似快照的方式将数据保存下来,这样读锁就和写锁不冲突了。不同的事务session会看到自己特定版本的数据,即使其他的事务更新了数据,但是对本事务仍然不可见,本事务看到的数据始终是第一次查询到的数据。在数据库中,这个快照的处理方式叫多版本并发控制(Multi-Version Concurrency Control)。这种方式真正实现了非阻塞读,只有在写操作时才需要加行级锁,因此并发效率更高。
在各个数据库系统的,MVCC的实现机制不尽相同,下面来详细介绍一下InnoDB是如何实现MVCC的,主要讨论可重复读级别的实现。
首先,需要了解两个概念:ReadView、undo log、可见性判断算法
ReadView
ReadView其实就是上面提到的快照,每个事务在启动后第一次执行查询时会创建一份快照,一个事务快照的创建过程可以概括为:
查看当前所有的未提交并活跃的事务,存储在数组中
选取未提交并活跃的事务中最小的XID,记录在快照的xmin中
选取未提交事务中最大的XID,记录快照在xmax中
ReadView主要是用来做可见性判断的,即通过ReadView可以知道:哪些事务的提交结果对当前事务可见,哪些事务的提交结果对当前事务不可见。关于如何判断可见性,后面部分会对可见性判断算法做出介绍。不过,我们可以先思考一个问题,在可重复读隔离级别中,哪些事务的提交结果对当前事务可见呢?
undo log
刚才介绍了ReadView的基础概念,提到了ReadView是事务的快照,但是通过ReadView仅仅能知道哪些事务的提交结果对当前事务可见,可是还是不知道当前事务的数据快照在哪啊。undo log就是来解决这个问题的。
undo log就是我们通常说的回滚日志,undo log存放的是数据的历史记录,也可以叫数据的快照。
当一个事务要提交修改时:
1.会用排他锁锁定该行
2.将该行修改前的值Copy到undo log segment(回滚段)。
3.修改当前行的值,将该行的回滚指针指向undo log中修改前的行。
参考网址
https://www.jianshu.com/p/398d788e1083
持久性(durability)
数据一旦修改,提交事务后,无法撤回.
python