当前位置: 代码迷 >> MySQL >> mysql-事务隔离级别
  详细解决方案

mysql-事务隔离级别

热度:378   发布时间:2016-05-05 16:19:17.0
mysql--事务隔离级别

1.事务具有ACID四种特性。

1.原子性(automicity):一个事务中的所有语句,应该做到:要么全做,要么一个都不做;
2.一致性(consisitency):让数据保持逻辑上的“合理性”,比如:一个商品出库时,既要让商品库中的该商品数量减1,又要让对应用户的购物车中的该商品加1;
3.隔离性(isolation):如果多个事务同时并发执行,但每个事务就像各自独立执行一样。
4.持久性(durability):一个事务执行成功,则对数据来说应该是一个明确的硬盘数据更改(而不仅仅是内存中的变化)

2. 事务的隔离级别及产生的相关问题

这里写图片描述

  1. 脏读 (dirty read)事务T1更新了一行记录的内容,但是并没有提交所做的修改。事务T2读取更新后的行,然后T1执行回滚操作,取消了刚才所做的修改。现在T2所读取的行就无效了。

  2. 不可重复读取 (nonrepeatable read)事务T1读取一行记录,紧接着事务T2修改 了T1刚才读取的那一行记录。然后T1又再次读取这行记录,发现与刚才读取的结果不同。这就称为“不可重复”读,因为T1原来读取的那行记录已经发生了变化。

  3. 幻读 (phantom read)事务T1读取一条指定的WHERE子句所返回的结果集。然后事务T2新插入 一行记录,这行记录恰好可以满足T1所使用的查询条件中的WHERE 子句的条件。然后T1又使用相同的查询再次对表进行检索,但是此时却看到了事务T2刚才插入的新行。这个新行就称为“幻像”,因为对T1来说这一行就像突 然出现的一样。

3.MySQL的InnoDB引擎中事物与锁

锁机制
1) 共享锁:由读表操作加上的锁,加锁后其他用户只能获取该表或行的共享锁,不能获取排它锁,也就是说只能读不能写。
2) 排它锁:由写表操作加上的锁,加锁后其他用户不能获取该表或行的任何锁,典型是mysql事务中的DML语句INSERT,DELETE,UPDATE.

锁的范围:
行锁: 对某行记录加上锁
表锁: 对整个表加上锁
这样组合起来就有,行级共享锁,表级共享锁,行级排他锁,表级排他锁。

3.1 SELECT …… LOCK IN SHARE MODE

在读取的行上设置一个共享模式的锁。这个共享锁允许其它会话(session)读取数据但不允许修改它。 行读取的是最新的数据,如果他被其它事务使用中而没有提交,读取锁将被阻塞知道那个事务结束。

3.2 SELECT ….. FOR UPDATE
在读取行上设置一个排他锁。组织其他session读取或者写入行数据

3.3 INSERT、UPDATE、DELETE
会话事务会对DML语句操作的数据加上一个独占锁,其他会话的事务都将会等待其释放独占锁。

3.4 gap and next key lock(间隙锁)
InnoDB引擎会自动给会话事务中的共享锁、更新琐以及独占锁,需要加到一个区间值域的时候,再加上个间隙锁(或称范围锁),对不存在的数据也锁住,防止出现幻读。

3.5表锁

LOCK TABLES tablename WRITE;LOCK TABLES tablename READ;UPDATE ....;UNLOCK TABLES;

4.mysql中innodb引擎演示REPEATABLE-READ

创建一个innodb引擎的表

CREATE TABLE t_innodb(`ID` int NOT NULL AUTO_INCREMENT,`NUM` int,PRIMARY KEY (`ID`))ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE utf8_general_ci;#表中插入一条记录INSERT INTO t_innodb (`ID`, `NUM`) VALUES (NULL, 1);

这里写图片描述

查看和设置设置隔离级别:

#查看InnoDB系统级别的事务隔离级别SELECT @@global.tx_isolation;#查看InnoDB会话级别的事务隔离级别SELECT @@tx_isolation;#设置InnoDB系统级别的事务隔离级别set @@global.tx_isolation = 'REPEATABLE-READ';#设置InnoDB会话级别的事务隔离级别set tx_isolation='REPEATABLE-READ';

这里写图片描述

在session 1中开启事务,并且修改字段num的值:

START TRANSACTION;UPDATE t_innodb SET num = num+ 1 WHERE id = 1;#修改num的值后,查询到num变成了2SELECT * from t_innodb WHERE id = 1;

这里写图片描述

在命令行窗口开启session 2
这里写图片描述

在session 1中commit事务
这里写图片描述

在session 2中
这里写图片描述

下面验证下EPEATABLE-READ会不会出现幻读
在session 1中再插入数据:
这里写图片描述

在 session 2中
这里写图片描述
可见:Mysql InnoDB的可重复读隔离级别和其他数据库的可重复读是有区别的,不会造成幻象读(phantom read)。
引用:
[1] MySQL中的行级锁SELECT FOR UPDATE 和LOCK IN SHARE MODE 区别
[2]mysql事务隔离级别以及有问题的读取(脏读,不可重复读,幻象读)
[3]MYSQL数据库事务处理和锁机制

  相关解决方案