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就会继续执行,如果过了超时时间,写锁还没有被释放,就会抛出异常。这种对整表加锁的方式自然没有脏读、不可重复读、和幻读的问题,但是也失去了并发的能力,性能很差。
来源:CSDN
作者:yiyefuchen
链接:https://blog.csdn.net/yiyefuchen/article/details/103456639