1. 数据并发问题

MySQL是一个客户端/服务器架构的软件,可以有若干个客户端与之连接,连接上之后,就可以称之为一个会话(Session),对于服务器来说可能同时处理多个Session,也就是对服务器来说可能同时处理多个事务。但是由于事务的隔离性,理论上如果多个事务有对同一个表中的数据进行的操作,他们的执行顺序应该按照事务到达的顺序进行排队(也叫序列化),但是这样对性能影响太大,比如SessionA,SessionB,SessionC都提交了一个事务,事务到达的顺序为A -> C -> B:

对比上面的图片我们发现虽然序列化可以满足事务的隔离性问题,但是对性能影响太大,难道就没有什么两全其美的方法吗?在解决问题之前,我们得先明白同时处理多个Session时可能会出现一系列并发问题,具体总结为以下几种:

脏写脏读不可重复读幻读

创建一个表tb_student,数据如下:

下面我将根据该表数据进行通过举例+说明的方式进行解释。

1.1 脏写(Dirty Write)

脏写示意图:

执行次序Session ASession B1事务开始2事务开始3UPDATE tb_student SET name = ‘lisi’ WHERE stu_id = 14UPDATE tb_student SET name = ‘wangwu’ WHERE stu_id = 15事务提交6事务回滚

前提事件: Session A和Session B各自开启了一个事务,并且他们都修改了同一个表的同一个字段 附加事件: Session A在将"zhangsan"修改为"wangwu"后并提交事务,Session B却回滚了事务 导致结果: 本该成功修改的"wangwu"又变回了"zhangsan",由于SessionA修改了一个未提交的数据,导致SessionA修改数据失败,这就是脏写问题。

1.2 脏读(Dirty Read)

脏读示意图:

执行次序Session ASession B1事务开始2事务开始3UPDATE tb_student SET name = ‘lisi’ WHERE stu_id = 14SELECT * FROM tb_student WHERE stu_id = 1;(此时name=“lisi”)5事务提交6事务回滚

前提事件: Session A和Session B各自开启了一个事务,Session A查询数据,Session B更改数据,它们的操作都是针对同一个表的。 附加事件: 并且Session A在查询数据之前,Session B对数据进行了修改。此时Session A 读到的数据name值为"lisi",但是由于Session B 回滚事务。 导致结果: name的实际值变又回了"zhangsan",此时Session A读到了一个未提交"脏数据",这就是脏读。

1.3 不可重复读(NON-REPEATED READ)

不可重复读示意图:

执行次序Session ASession B1事务开始2事务开始3SELECT * FROM tb_student WHERE stu_id = 1;(此时name=“zhangsan”)4UPDATE tb_student SET name = ‘lisi’ WHERE stu_id = 15事务提交6SELECT * FROM tb_student WHERE stu_id = 1;(此时name=“lisi”)7事务提交

前提事件: Session A和Session B各自开启了一个事务,Session A查询数据, Session B更改数据,它们的操作都是针对同一个表的

附加事件: Session A的事务中进行了两次(或多次)查询,在两次查询之间,Session B中的事务对表中的数据进行了修改。

导致结果: 两次(或多次)查询的结果不一样,这就是不可重复读问题。

1.4 幻读(Phantom)

幻读示意图:

执行次序Session ASession B1事务开始2事务开始3SELECT * FROM tb_student(此时只读到一条数据)4INSERT INTO tb_student VALUES(2,‘lisi’,‘男’,19)5事务提交6SELECT * FROM tb_student;(此时读到了两条数据)7事务提交

前提条件: Session A和Session B各自开启了一个事务,Session A查询多条数据, Session B插入新数据,它们的操作都是针对同一个表的

附加条件: Session A的事务中进行了两次(或多次)查询,在两次查询之间,Session B中的事务在表中新增数据。

导致结果: SessionA再次读取同一个表,读到了先前没读到的记录,就像产生了幻觉,这就是幻读问题。

2. 四种隔离级别

前面所提到的并发问题亦有轻重之分:脏写 > 脏读 > 不可重复读 > 幻读

我们可以为了提高性能,根据业务的需要进行一定的取舍,这时就需要通过设置隔离级别来实现了,接下来我来为大家介绍一下SQL中的四种隔离级别,以及分别解决了前面提到的哪些并发问题。

注意:由于脏写问题太过恶劣,数据库不允许这种行为,因此所有的隔离级别都是在解决脏写问题的前提下谈的。

SQL标准中设立了下面4种隔离级别(级别从低到高):

READ UNCOMMITTED:读未提交,在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。不能避免脏读、不可重复读、幻读。 READ COMMITED:读已提交:它满足了隔离的简单定义:一个事务只能看见已提交事务所做的改变。这是绝大多数数据库系统的隔离级别(MySQL不是)。可以避免脏读。 REPEATABLE READ:可重复读,如果事务B对表中的数据进行了修改并提交,那么事务A多次读到的数据内容都相同。可以避免脏读、不可重复读,这也是MySQL中的默认隔离级别。 SERIALIZABLE:可序列化,确保事务可以从一个表中读取相同的行。在这个事务持续期间,禁止其他事务对该表进行任何操作。解决了所有并发问题,但是性能十分低下。 可总结为下面的表格:

隔离级别解决脏读解决不可重复读解决幻读READ UNCOMMITTEDNONONOREAD COMMITEDYESNONOREPEATABLE READYESYESNOSERIALIZABLEYESYESYES

推荐文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: