Mysql-事务(二)

ぃ、小莉子 提交于 2019-12-11 07:49:13

1.事务的并发问题

脏读:事务A读取了事务B更新的数据,然后B进行了回滚操作,这时A读到的数据就是脏数据,侧重于一个事务读取了另一个未提交事务修改的数据。

不可重复读:事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据作了更新并提交(和脏读不一样的地方),导致事务A多次读取同一数据时,结果不一致。

幻读:系统管理员A将数据库中所有学生的成绩从具体分数改未ABCD,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条计数没有改过来,就好像发生了幻觉一样,这就叫幻读。

小结:脏读侧重于一个事务读取了另一个未提交事务操作的数据,不可重复读侧重于一个事务读取到了另一个已提交事务修改的数据,幻读侧重于一个事务读取到了另一个已提交事务新增或删除的数据。

2.事务隔离级别概述

        mysql中,innodb所提供的事务符合ACID的要求,而事务通过事务日志中的redo log和undo log满足了原子性、一致性、持久性,事务还会通过锁机制满足隔离性,在innodb存储引擎中,有不同的隔离级别,它们有着不同的隔离性,一共有如下4中:

       READ-UNCOMMITED:读未提交

       READ-COMMITED:读已提交,解决了脏读问题

       REPEATABLE-READ:可重复读,默认,解决了脏读和不可重复读问题

       SERIALIZABLE:串行化,解决了脏读、不可重复读和幻读问题

mysql可以通过如下语句查看和修改隔离级别:

      > show session variables like '%isolation%'; (session可省略)

      > show global variables like '%isolation%'; 

      > set session tx_isolation = 'READ-UNCOMMITTED';

         或 set session transaction_isolation = 'READ-UNCOMMITTED';

      > set global tx_isolation = 'READ-UNCOMMITTED';

         或 set global transaction_isolation = 'READ-UNCOMMITTED';

如果需要修改my.cnf配置文件,则可通过如下参数配置mysql的事务隔离级别,注意,不是使用tx_isolation,而是使用transaction_isolation:

      transaction_isolation=REPEATABLE-READ

3.隔离级别-读未提交

测试用例如下图:

开启两个会话,并分别开始事务

会话1删除第三条数据                     (1)

会话2查询,可以看到少一条数据    (2)

 由上图可以看出,会话一删除一条数据还没有提交事务,会话2就可以看到数据少了一条。当前事务能够看到别的事务中未提交的数据,这种现象称之为"脏读",事务1可能对事务进行回滚,此时,事务2看到的数据就是脏数据,由此可以推断出,这种隔离级别一定也会存在"不可重复读"和幻读的问题。

4. 隔离级别-读已提交

测试用例如下图:

两个会话都开启了事务

会话1先将第三条数据的province_id更新为55        (1)

会话2查询,没有查询到更新数据                           (2)

会话1提交事务                                                        (3)

会话2查询,可以查询到更新数据                           (4)

 从测试用例中可以知道:会话2在会话1未提交事务之前查询不到会话1修改的数据,这就解决了脏读的问题,可以在会话1提交事务后查询到会话1修改的数据,这种隔离级别就被称为"读提交"。从测试中还可以看出,会话2在没有提交事务前,没有操作任何数据,两次查询的数据不一样,说明,这种隔离级别存在不可重复读的问题,由此推断,也会存在幻读的问题。

5. 隔离级别-可重复读

测试用例如下图:

两个会话都开启了事务

会话1先将第三条数据的province_id更新为33    (1)

会话1插入一条数据                                            (2)

会话1查询                                                           (3)

会话2查询,没有查询到更新和新增的数据         (4)

会话1提交事务                                                    (5)

会话2查询,没有查询到更新和新增的数据         (6)

会话2将所有数据的city_name都更新为"深圳"     (7)

会话2查询,发现第三条数据的province_id被更新为33,多了一条数据,所有数据的city_name都更新为"深圳"  (8)

会话2提交事务                                                   (9)

会话1查询,所有数据的city_name都更新成了"深圳"               (10)

 从样例中可以知道,会话1分别更新(1)和新增(2)了一条数据,会话2没有查询到(4),说明重复读的隔离级别解决了脏读问题。

当会话1提交了事务(5),会话2查询,还是没有查询到变化,说明对于以没有对数据做任何操作为前提条件下的查询来说,重复读隔离策略解决了不可重复读和幻读(大部分)的问题。

然后会话2把所有数据都的city_name都更新成了”深圳“,然后查询,此时看到了会话1更新和新增的数据(?)

6. 隔离级别-可重复读

测试用例如下图:

两个会话都开启了事务

会话1先插入一条数据     (1)

会话2查询                       (2)

 从测试用例中可以知道:会话2查询,在会话1事务没有提交之前会阻塞,等待一段时间后会抛出一个异常,从错误信息可以发现,会话2中的事务锁请求超时了,我们知道,事务的隔离性是由锁来实现的,当我们使用串行化的隔离级别时,由于事务1先对表添加了写锁,所以当事务2对表请求读锁时,会被阻塞,如果在超时时间内,事务1提交了事务,即释放了写锁,事务2就会继续执行,如果过了超时时间,写锁还没有被释放,就会抛出异常。这种对整表加锁的方式自然没有脏读、不可重复读、和幻读的问题,但是也失去了并发的能力,性能很差。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!