您的位置:首页 > 数据库 > MySQL

mysql 事务隔离

2015-11-04 00:00 766 查看
摘要: READ UNCOMMITTED 读未提交
READ COMMITTED 读提交
REPEATABLE 可重读
SERIALIABLE 可串读

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息