MySQL四种事务隔离级别详解及对⽐
MySQL 四种事务隔离级别详解及对⽐
按照SQL:1992 事务隔离级别,InnoDB默认是可重复读的(REPEATABLE READ)。MySQL/InnoDB 提供SQL标准所描述的所有四个事务隔离级别。你可以在命令⾏⽤--transaction-isolation选项,或在选项⽂件⾥,为所有连接设置默认隔离级别。
例如,你可以在my.inf⽂件的[mysqld]节⾥类似如下设置该选项:
transaction-isolation = {READ-UNCOMMITTED | READ-COMMITTED | REPEATABLE-READ | SERIALIZABLE}
⽤户可以⽤SET TRANSACTION语句改变单个会话或者所有新进连接的隔离级别。它的语法如下:
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
注意:默认的⾏为(不带session和global)是为下⼀个(未开始)事务设置隔离级别。如果你使⽤GLOBAL关键字,语句在全局对从那点开始创建的所有新连接(除了不存在的连接)设置默认事务级别。
你需要SUPER权限来做这个。使⽤SESSION 关键字为将来在当前连接上执⾏的事务设置默认事务级别。任何客户端都能⾃由改变会话隔离级别(甚⾄在事务的中间),或者为下⼀个事务设置隔离级别。
你可以⽤下列语句查询全局和会话事务隔离级别:
SELECT @@_isolation;
SELECT @@_isolation;
SELECT @@tx_isolation;
----以上⼿册中的理论知识;
===========================================================================================隔离级别脏读(Dirty Read)不可重复读(NonRepeatable Read)幻读(Phantom Read)
===========================================================================================
未提交读(Read uncommitted)可能可能可能
已提交读(Read committed)不可能可能可能
可重复读(Repeatable read)不可能不可能可能
可串⾏化(Serializable )不可能不可能不可能
===========================================================================================
·未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据
·提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)
·可重复读(Repeated Read):可重复读。在同⼀个事务内的查询都是事务开始时刻⼀致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读
·串⾏读(Serializable):完全串⾏化的读,每次读都需要获得表级共享锁,读写相互都会阻塞
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
⽤例⼦说明各个级别的情况:
①脏读: 脏读就是指当⼀个事务正在访问数据,并且对数据进⾏了修改,⽽这种修改还没有提交到数据库中,这时,另外⼀个
事务也访问这个数据,然后使⽤了这个数据。
session 1:
mysql> select @@_isolation;
+-----------------------+
| @@_isolation |
+-----------------------+
| REPEATABLE-READ    |
+-----------------------+
1 row in set (0.00 sec)
mysql> select @@_isolation;
+-----------------------+
| @@_isolation |
+-----------------------+
| REPEATABLE-READ    |
+-----------------------+
1 row in set (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into ttd values(1);
Query OK, 1 row affected (0.05 sec)
mysql> select * from ttd;
+------+
| id  |
+------+
mysql查看所有存储过程
|  1 |
+------+
1 row in set (0.00 sec)
session 2:
mysql> select @@_isolation;
wordpress建站视频教程+------------------------+
| @@_isolation |
+------------------------+
| REPEATABLE-READ    |
+------------------------+
1 row in set (0.00 sec)
mysql> select @@_isolation;
+-----------------------+
| @@_isolation |
+-----------------------+
| REPEATABLE-READ  |    --------该隔离级别下(除了 read uncommitted)
+-----------------------+
1 row in set (0.00 sec)
mysql> select * from ttd;
Empty set (0.00 sec)      --------不会出现脏读
mysql> set session transaction isolation level read uncommitted;
Query OK, 0 rows affected (0.00 sec)
mysql> select @@_isolation;
+------------------------+
| @@_isolation |
+------------------------+
| READ-UNCOMMITTED    |  --------该隔离级别下
+------------------------+
1 row in set (0.00 sec)
mysql> select * from ttd;
+------+
| id  |
+------+
|  1 |                    --------REPEATABLE-READ级别出现脏读
+------+
1 row in set (0.00 sec)
结论:session 2 在READ-UNCOMMITTED 下读取到session 1 中未提交事务修改的数据.
②不可重复读:是指在⼀个事务内,多次读同⼀数据。在这个事务还没有结束时,另外⼀个事务也访问该同⼀数据。那么,在第⼀个事务中的两次读数据之间,由于第⼆个事务的修改,那么第⼀个事务两次读到的的数据可能是不⼀样的。这样就发⽣了在⼀个事务内两次读到的数据是不⼀样的,因此称为是不可重复读。
session 1:
mysql> select @@_isolation;
+------------------------+
| @@_isolation |
+------------------------+
| READ-COMMITTED    |
+------------------------+
1 row in set (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from ttd;
+------+
| id  |
+------+
|  1 |
+------+
1 row in set (0.00 sec)
session 2 :
mysql> select @@_isolation;
+------------------------+
| @@_isolation |
+------------------------+
| REPEATABLE-READ    |
+------------------------+
1 row in set (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from ttd;
+------+
| id  |
+------+
|  1 |
+------+
1 row in set (0.00 sec)
mysql> insert into ttd values(2); /也可以更新数据
Query OK, 1 row affected (0.00 sec)
mysql> select * from ttd;
+------+
| id  |
+------+
|  1 |
|  2 |
+------+
2 rows in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.02 sec)
session 2 提交后,查看session 1 的结果;
session 1:
mysql> select * from ttd;
+------+
| id  |
+------+
|  1 |              --------和第⼀次的结果不⼀样,READ-COMMITTED 级别出现了不重复读|  2 |
+------+
2 rows in set (0.00 sec)
③可重复读:
session 1:
mysql> select @@_isolation;
+------------------------+
| @@_isolation |
+------------------------+
| REPEATABLE-READ    |
+------------------------+
1 row in set (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from ttd;
+------+
| id  |
+------+
|  1 |
|  2 |
+------+
2 rows in set (0.00 sec)
session 2 :
mysql> select @@_isolation;
+------------------------+
| @@_isolation |
+------------------------+
| REPEATABLE-READ    |
+------------------------+
1 row in set (0.00 sec)
英语基础教程
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into ttd values(3);
Query OK, 1 row affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.03 sec)
session 2 提交后,查看session 1 的结果;
session 1:
mysql> select * from ttd;
+------+
| id  |
+------+
|  1 |                  --------和第⼀次的结果⼀样,REPEATABLE-READ级别出现了重复读
|  2 |
+------+
2 rows in set (0.00 sec)
(commit session 1 之后再select * from ttd 可以看到session 2 插⼊的数据3)
④幻读:第⼀个事务对⼀个表中的数据进⾏了修改,这种修改涉及到表中的全部数据⾏。同时,第⼆
个事务也修改这个表中的数据,这种修改是向表中插⼊⼀⾏新数据。那么,以后就会发⽣操作第⼀个事务的⽤户发现表中还有没有修改的数据⾏,就好象发⽣了幻觉⼀样。
mysql>CREATE TABLE `t_bitfly` (
`id` bigint(20) NOT NULL default '0',
`value` varchar(32) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
mysql> select @@_isolation, @@tx_isolation;
+-----------------------+-----------------+
| @@_isolation | @@tx_isolation |
+-----------------------+-----------------+
| REPEATABLE-READ    | REPEATABLE-READ |
+-----------------------+-----------------+
实验⼀:
t Session A          Session B
|
| START TRANSACTION;    START TRANSACTION;
|
| SELECT * FROM t_bitfly;
| empty set
|              INSERT INTO t_bitfly
|              VALUES (1, 'a');
|
| SELECT * FROM t_bitfly;
| empty set
|              COMMIT;
|
| SELECT * FROM t_bitfly;
| empty set
|
| INSERT INTO t_bitfly VALUES (1, 'a');
| ERROR 1062 (23000):
| Duplicate entry '1' for key 1
v (shit, 刚刚明明告诉我没有这条记录的)
如此就出现了幻读,以为表⾥没有数据,其实数据已经存在了,傻乎乎的提交后,才发现数据冲突了。
实验⼆:
t Session A        Session B
世荣兆业最新公告
|
| START TRANSACTION;    START TRANSACTION;
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id  | value |
| +------+-------+
| |  1 | a  |
| +------+-------+
|              INSERT INTO t_bitfly
|              VALUES (2, 'b');
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id  | value |
| +------+-------+
| |  1 | a  |
| +------+-------+
|              COMMIT;
|
| SELECT * FROM t_bitfly;威尔士vs英格兰谁会赢啊
| +------+-------+
| | id  | value |
| +------+-------+
| |  1 | a  |
| +------+-------+
|
| UPDATE t_bitfly SET value='z';
| Rows matched: 2 Changed: 2 Warnings: 0
| (怎么多出来⼀⾏)
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id  | value |
| +------+-------+
| |  1 | z  |
| |  2 | z  |
| +------+-------+
本事务中第⼀次读取出⼀⾏,做了⼀次更新后,另⼀个事务⾥提交的数据就出现了。也可以看做是⼀种幻读。
当隔离级别是可重复读,且禁⽤innodb_locks_unsafe_for_binlog的情况下,在搜索和扫描index的时候使⽤的next-key locks可以避免幻读。
再看⼀个实验,要注意,表t_bitfly⾥的id为主键字段。
实验三:
t Session A        Session B
|
| START TRANSACTION;    START TRANSACTION;
|
| SELECT * FROM t_bitfly
| WHERE id<=1
html空格代码只能显示一个
| FOR UPDATE;
| +------+-------+
| | id  | value |
| +------+-------+
| |  1 | a  |
| +------+-------+
|              INSERT INTO t_bitfly
|              VALUES (2, 'b');
|              Query OK, 1 row affected
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id  | value |
| +------+-------+
| |  1 | a  |
| +------+-------+

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。