事务

事务是一组原子性的SQL,事务中的语句要么全部执行成功,要么全部执行失败。事务具有ACID属性,

原子性,(Atomicity)一个事务必须被视为一个不可分割的最小工作单元,整个事务中的操作要么全部执行成功,要么全部执行失败

一致性,(consistency)数据库总是从一个一致性的状态转换到另一个一致性的状态。事务没有提交,事务中的修改也不会保存到数据库中

隔离性,(isolation)通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的

持久性,(durability)一旦事务提交,则所作的修改就会永久保存在数据库中

隔离级别:

每一种级别都规定了一个事务中所做的修改,哪些在事务内和事务间是可见的,哪些是不可见的。读未提交,读已提交,可重复读,串行化

隔离级别

当数据库上有多个事务同时执行的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)的问题,为了解决这些问题,就有了“隔离级别”的概念。

SQL标准的事务隔离级别: 读未提交、读提交、可重复读、串行化。

  • 读未提交(Read Uncommitted): 一个事务还没提交时,它做的变更就能被别的事务看到。
  • 读提交(Read Committed): 一个事务提交之后,它做的变更才会被其他事务看到。
  • 可重复读(Repeatable Read): 一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。是MYSQL默认的事务隔离机制,Innodb引擎中通过多版本并发控制(MVCC),解决了幻读问题。
  • 串行化(Serializable): 顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

Mysql的默认隔离级别就是可重复读

例如:
假设数据表T中只有一列,其中一行的值为1,下面是按照时间顺序执行两个事务的行为。

create table T(c int) engine = InnoDB;

insert into T(c) values(1);

clipboard.png

我们来看看在不同的隔离级别下,事务A会有哪些不同的返回结果,也就是图里面V1、V2、V3的返回值分别是什么。

若隔离级别是“读未提交”, 则V1的值就是2。这时候事务B虽然还没有提交,但是结果已经被A看到了。因此,V2、V3也都是2。

若隔离级别是“读提交”,则V1是1,V2的值是2。事务B的更新在提交后才能被A看到。所以, V3的值也是2。

若隔离级别是“可重复读”,则V1、V2是1,V3是2。之所以V2还是1,遵循的就是这个要求:事务在执行期间看到的数据前后必须是一致的。

若隔离级别是“串行化”,则在事务B执行“将1改成2”的时候,会被锁住。直到事务A提交后,事务B才可以继续执行。所以从A的角度看, V1、V2值是1,V3的值是2。


总结:

脏读:
当数据库中一个事务A正在修改一个数据但是还未提交或者回滚,另一个事务B 来读取了修改后的内容并且使用了,之后事务A提交了,此时就引起了脏读。

此情况仅会发生在: 读未提交的的隔离级别.

不可重复读:
在一个事务A中多次操作数据,在事务操作过程中(未最终提交),事务B也才做了处理,并且该值发生了改变,这时候就会导致A在事务操作的时候,发现数据与第一次不一样了。 就是不可重复读。

此情况仅会发生在:读未提交、读提交的隔离级别.

幻读:

一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为幻读。

幻读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还存在没有修改的数据行,就好象发生了幻觉一样.

一般解决幻读的方法是增加范围锁RangeS,锁定检索范围为只读,这样就避免了幻读。

此情况会回发生在:读未提交、读提交、可重复读的隔离级别.

幻读举例子:

事务1:
clipboard.png

 事务2:
clipboard1.png

首先创建一张数据表,字段id,value;
插入5条数据;
启动事务1,查询发现只有5条数据
启动事务2,查询发现只有5条数据,然后插入第六条数据,id=6,value=6,并且提交;
事务1插入第六条数据,插入失败,明明查询出来id=6的数据不存在,但是插入的时候说数据已经存在,这就是幻读。

针对这四种隔离级别,应该根据具体的业务来取舍,如果某个系统的业务里根本就不会出现重复读的场景,完全可以将数据库的隔离级别设置为 RC,这样可以最大程度的提高数据库的并发性。
数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔离实质上就是使事务在一定程度上“串行化”进行.


隔离的实现
隔离的实现主要有读写锁和MVCC(Multi-VersionConcurrency Control)多版本并发处理方式。MVCC是一种多版本并发控制机制。锁机制可以控制并发操作,但是其系统开销较大,而MVCC可以在大多数情况下代替行级锁,使用MVCC,能降低其系统开销。具体内容,详见其他文章。


阿阿阿黄
34 声望4 粉丝