1、事务

(1)事务的概念

事务由单独单元的一个或多个SQL语句组成,在这 个单元中,每个MySQL语句是相互依赖的。而整个单独单 元作为一个不可分割的整体,如果单元中某条SQL语句一 旦执行失败或产生错误,整个单元将会回滚。所有受到影 响的数据将返回到事物开始以前的状态;如果单元中的所 有SQL语句均执行成功,则事物被顺利执行。

(2)事务的acid属性

a. 原子性(Atomicity) 原子性是指事务是一个不可分割的工作单位,事务中的操作要么 都发生,要么都不发生。 

b. 一致性(Consistency) 事务必须使数据库从一个一致性状态变换到另外一个一致性状态 。 

c. 隔离性(Isolation) 事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个 事务内部的操作及使用的数据对并发的其他事务是隔离的,并发 执行的各个事务之间不能互相干扰。 

d. 持久性(Durability) 持久性是指一个事务一旦被提交,它对数据库中数据的改变就是 永久性的,接下来的其他操作和数据库故障不应该对其有任何影 响

 

(3)事务的创建步骤

步骤一:开启事务

set autocommit = 0;   #在开启事务前需要关闭自动提交,0代表off,1代表on,当此语句执行时默认开启事务,因此开启事务语句可选则执行

start transaction;   #可选

步骤二:编写事务中的sql语句(select 、update、delete、insert)

步骤三:结束事务

commit; #提交

rollback #回滚

2、没有隔离机制会产生的问题

对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没 有采取必要的隔离机制, 就会导致各种并发问题,如脏读、不可重复读、幻读。

其中涉及到的相关命令如下:

#查看隔离级别

select @@tx_isolation;

#设置隔离级别

set session transcarion isolation level 隔离级别;

 

(1)脏读

对于两个事务T1和T2,如果T1对数据进行了修改,但还没有提交或者回滚(相当于撤销之前的修改)时,T2读取该数据,此时T2读取到的是已经修改后的数据。当T1进行回滚后,T2再次读取数据,此时数据为原数据(修改前的数据)。

示例:

现有学生表如下所示。(注意:每个小节提到的原始表就是指此时的学生表)

MYSQL学习笔记——事务

 

当教师a通过事务t1将学号为1的学生姓名修改为“john”,并没有提交或者回滚时,教师b通过事务t2将查看学生表stu,此时其看到的是下面的数据:

Id

name

1

john

2

李四

然后教师a撤回了其修改的操作(回滚)。此时,教师b再次通过事务t2,查看学生表stu,其看到的数据为:

Id

name

1

张三

2

李四

      因此,教师a修改数据后且没有提交或回滚时,教师b能够查看到的数据是修改后的数据,而当教师a回滚后,教师b再次通过相同事务查询到的数据时原数据的这种现象就称为脏读。

(2)不可重复读

在同一事务中多次查询相同数据,然而查询结果不一致,这种现象称为不可重复读。

例如,在上述示例中,教师b在同一个事务中查询学生表,第一次为修改后的数据,第二次为原始数据,两次查询的结果不一致,因此存在不可重复读的现象。

(3)幻读

对事务T1和T2,T1读取表中数据为n行,T2向表中新插入m行数据,此时T1再次读取表中数据为n+m行,这种现象就称为幻读。

例如上述示例,教师a在事务t1中将表中所有姓名全部换成“john”(update stu set name = ‘john’;),将是2行数据受到影响(没有提交或回滚),此时教师b在事务t2中插入一行新数据并提交,这个时候教师a再次将表中姓名全部换成‘lucy‘,此时将是3行数据受到影响。

3、隔离级别

隔离级别

描述

read uncommitted (读取未提交数据)

允许事务读取被其他事务变更,这个级别脏读、不可重复读、幻读等问题都会出现。

read committed

(读取提交数据)

只允许事务读取被其他事务提交的变更,该级别可以避免脏读问题,但是不能避免不可重复读和幻读的问题。

repeatable read

(可重复读)

确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,不允许其他事务对这个字段进行变更,可以避免脏读、不可重复读问题,不能避免幻读的问题。

serializable

(串行化)

确保事务可以从一个表中读取相同的行。在这个事务持续期间,禁止其他事务对这个表进行插入、删除、更新等操作,所有并发问题都可以解决,但是性能十分低下。

下面将分别介绍设置隔离级别为read committed、read committed、serializable后产生的效果。

注意下面各个示例中提到的事务t1和t2都是提前设置好相同隔离级别的前提下进行的操作。

(1)read committed

设置隔离级别为read committed后,如上述示例。当教师a通过事务t1将学号为1的学生姓名修改为“john”,并没有提交或者回滚时,教师b通过事务t2将查看学生表stu,此时其看到的是没有修改的数据:

Id

name

1

张三

2

李四

当教师a通过事务t1修改数据并提交后,教师b再次通过事务t2将查看学生表stu,此时其看到的是已经修改的数据,进而避免了脏读。

Id

name

1

john

2

李四

2)repeatable read

设置隔离级别为repeatable read后,如上述示例。教师a通过事务t1修改原始stu表中数据(如将张三改成王五)且没有提交时,教师b通过事务t2查看学生表stu,此时其看到的数据如下:

Id

name

1

张三

2

李四

当教师a结束事务t1后(即提交了),教师b再次通过事务t2查看学生表stu,此时其看到的数据仍然不变,具体如下:

Id

name

1

张三

2

李四

然而,当教师b也结束事务t2(即提交了)后,其再次查看学生表stu时,其看到的是已经修改后的数据,即:

Id

name

1

王五

2

李四

3)serializable

设置隔离级别为repeatable read后,如上述示例。教师a通过事务t1对将学生表stu(原始表共有两行数据)中所有的姓名全部替换成“unknown”,在教师a还未执行修改操作时,教师b通过事务t2插入一行新的数据,并执行,此时发现教师b的操作无法执行,一直处于等待的状态,而当教师a的修改操作执行并结束事务t1(即提交了)之后时,教师b的插入操作才能执行。

教师a的操作:输入update后未执行。

MYSQL学习笔记——事务

 

教师b的操作:在教师a未执行update时,教师b的insert操作一直等待无法执行。

MYSQL学习笔记——事务

 

当教师a执行update,并提交后,教师b的操作方可执行,如下图所示。

教师a的操作:

由于教师b的插入未执行,所以只有两行受影响,因此避免了幻读的问题。

MYSQL学习笔记——事务

 

教师b的操作:

MYSQL学习笔记——事务

 

此时教师b查看stu看到的数据为

 

MYSQL学习笔记——事务

相关文章: