Read uncommitted(读取未提交内容)
在该隔离级别,所有的事务都可以看到其他未提交的事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他的级别好多少。读取未提交的数据,也被称为脏读。
模拟实例: 需要两个终端
#注意,切换隔离级别建议退出mysql终端重新登录,否则有可能修改失败 A终端: #设置可以隔离模式 mysql> set global tx_isolation="READ-UNCOMMITTED"; Query OK, 0 rows affected (0.00 sec) mysql> select @@tx_isolation; +------------------+ | @@tx_isolation | +------------------+ | READ-UNCOMMITTED | +------------------+ 1 row in set (0.00 sec) mysql> use wangdk; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> desc user; +-------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+------------------+------+-----+---------+----------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | name | char(20) | NO | | | | +-------+------------------+------+-----+---------+----------------+ 2 rows in set (0.00 sec) mysql> select * from user; Empty set (0.00 sec) #开启事务 mysql> begin; Query OK, 0 rows affected (0.00 sec) #注意这里并未提交 commit mysql> insert into user(name) values("test"); Query OK, 1 row affected (0.00 sec) mysql> rollback; Query OK, 0 rows affected (0.00 sec)
B终端: mysql> set global tx_isolation="READ-UNCOMMITTED"; Query OK, 0 rows affected (0.00 sec) mysql> select @@tx_isolation; +------------------+ | @@tx_isolation | +------------------+ | READ-UNCOMMITTED | +------------------+ 1 row in set (0.00 sec) mysql> use wangdk; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed #注意:A终端并未 commit 提交事务。这里已经可以查到这个事务的数据,但是数据随时可以回滚的。 mysql> select * from user; +----+------+ | id | name | +----+------+ | 12 | test | +----+------+ 1 row in set (0.00 sec) #A终端 rollback 后数据消失 mysql> select * from user; Empty set (0.00 sec)
READ-COMMITTED (读取提交内容)
这是大多数数据库系统的默认系统隔离级别(但不是mysql默认的)。它满足了隔离的简单定义:事务的数据只有被提交才能被查询到。这种隔离级别也成为不可重复读,
以为同一事务的其他实例处理期间可能会有新的commit,所以同一个select会有不同的结果。
A终端: mysql> set global tx_isolation="READ-COMMITTED"; Query OK, 0 rows affected (0.00 sec) mysql> select @@tx_isolation; +----------------+ | @@tx_isolation | +----------------+ | READ-COMMITTED | +----------------+ 1 row in set (0.00 sec) mysql> use wangdk; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> select * from user; +----+------+ | id | name | +----+------+ | 13 | 1 | | 14 | 2 | | 15 | 4 | +----+------+ 3 rows in set (0.00 sec) mysql> begin; Query OK, 0 rows affected (0.00 sec) #删除一条数据,未提交事务 mysql> delete from user where id = 15; Query OK, 1 row affected (0.00 sec) #删除后A终端已经发生变化 mysql> select * from user; +----+------+ | id | name | +----+------+ | 13 | 1 | | 14 | 2 | +----+------+ 2 rows in set (0.00 sec)
B终端:
mysql> set global tx_isolation="READ-COMMITTED"; Query OK, 0 rows affected (0.00 sec) mysql> select @@tx_isolation; +----------------+ | @@tx_isolation | +----------------+ | READ-COMMITTED | +----------------+ 1 row in set (0.00 sec) mysql> use wangdk; Database changed mysql> select * from user; +----+------+ | id | name | +----+------+ | 13 | 1 | | 14 | 2 | | 15 | 4 | +----+------+ 3 rows in set (0.00 sec) #事务未提交B终端未发生变化 mysql> select * from user; +----+------+ | id | name | +----+------+ | 13 | 1 | | 14 | 2 | | 15 | 4 | +----+------+ 3 rows in set (0.00 sec)
Repeatable READ (可以重复读)
这是Mysql默认的事务隔离级别,它确保同一事务的多个实例在并发读数据时候,会看到同样的数据行。不过理论上,这会导致另一个问题(幻读)
(Phantom Read)简单的说,幻读是指永固读取某一个范围的数据行时,另一个事务又在该范围内插入了新行,当用户在读取该范围的
数据行是,会发现有新的幻影行,Innodb和falcon存储引擎通过多版本并发控制解决该问题 (MVCC,Multiversion Concurrency Control)机制
理解:A begin 读取的数据 和 B begin 读取的数据相同,如果B插入了数据,并commit ,A等待自己的事务完毕后才能重新读取B事务提交的数据。
模拟: A终端: mysql> select @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ 1 row in set (0.00 sec) mysql> begin; Query OK, 0 rows affected (0.00 sec) B终端 mysql> select @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ 1 row in set (0.00 sec) mysql> select * from user; +----+--------+ | id | name | +----+--------+ | 21 | wangdk | +----+--------+ 1 row in set (0.00 sec) mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> insert into user(name) values("hello"); Query OK, 1 row affected (0.01 sec) mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> select * from user; +----+--------+ | id | name | +----+--------+ | 21 | wangdk | | 22 | hello | +----+--------+ 2 rows in set (0.00 sec) A终端: #并未查找到B事务的数据 mysql> select * from user; +----+--------+ | id | name | +----+--------+ | 21 | wangdk | +----+--------+ 1 row in set (0.00 sec) mysql> commit; #必须等待A事务完成,才能读取到B事务已经提交上来的数据 mysql> select * from user; +----+--------+ | id | name | +----+--------+ | 21 | wangdk | | 22 | hello | +----+--------+ 3 rows in set (0.00 sec)
Serializable(可串行化)
这种最高的隔离级别,它通过强制事务排序,使之不能相互冲突。从而解决幻读的问题。简而言之,它是在每个读的数据行上加上共享锁
在这个级别,可能导致大量的超时和锁竞争
实例: A终端: mysql> select @@tx_isolation; +----------------+ | @@tx_isolation | +----------------+ | SERIALIZABLE | +----------------+ 1 row in set (0.00 sec) mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from wangdk.user; +----+--------+ | id | name | +----+--------+ | 21 | wangdk | | 22 | hello | | 23 | hello | +----+--------+ 3 rows in set (0.00 sec) #先不要提交,要先操作B终端,最后一句在执行commit mysql> commit; Query OK, 0 rows affected (0.00 sec) B 终端: mysql> select @@tx_isolation; +----------------+ | @@tx_isolation | +----------------+ | SERIALIZABLE | +----------------+ 1 row in set (0.01 sec) mysql> select * from wangdk.user; +----+--------+ | id | name | +----+--------+ | 21 | wangdk | | 22 | hello | | 23 | hello | +----+--------+ 3 rows in set (0.00 sec) #看到了么,更新秒数,等待A终端commit以后,这一句才会执行 mysql> update wangdk.user set name="wangdk1" where id = 21; Query OK, 1 row affected (17.09 sec) Rows matched: 1 Changed: 1 Warnings: 0