在标准的四个事务隔离级别中,可重复读这个隔离级别会出现幻读,但是各个数据库对隔离级别的具体实现是不一样的。Mysql中,在可重复读的隔离级别下,通过MVCC(多版本并发控制)避免了幻读,但不能说是完全避免了,在以下场景下:有更新的update语句,而且update语句影响到了insert的记录,还是会出现幻读,例子如下:
表结构:create table userinfo (id int primary key auto_increment,name varchar(10));
表中有数据:1,a
session1 session2
------------------------------------------------------------------------------------------------------------
时间点1 start transaction; start transaction;
------------------------------------------------------------------------------------------------------------
时间点2 select * from userinfo; select * from userinfo;
id name id name
1 a 1 a
-----------------------------------------------------------------------------------------------------------
时间点3 insert into userinfo(name) values ('b') ;
------------------------------------------------------------------------------------------------------------
时间点4 select * from userinfo; select * from userinfo;
id name id name
1 a 1 a
2 b
-------------------------------------------------------------------------------------------------------------
时间点5 commit;
-------------------------------------------------------------------------------------------------------------
时间点6 select * from userinfo
id name
1 a
select max(id) from userinfo;
max(id)
1
---------------------------------------------------------------------------------------------------------------
时间点7 update userinfo set name = 'c'
----------------------------------------------------------------------------------------------------------------
时间点8 select * from userinfo;
id name
1 c
2 c
select max(id) from userinfo;
max(id)
2
----------------------------------------------------------------------------------------------------------------
用户可以用SET TRANSACTION语句改变单个会话或者所有新进连接的隔离级别。它的语法如下:
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
注意:默认的行为(不带session和global)是为当前会话下一个(未开始)事务设置隔离级别。
如果你使用GLOBAL关键字,语句在全局对从那点开始创建的所有新连接(除了不存在的连接)设置默认事务级别。你需要SUPER权限来做全局设置。
使用SESSION 关键字为将来在当前连接上执行的事务设置默认事务级别。 任何客户端都能自由改变会话隔离级别(甚至在事务的中间),或者为下一个事务设置隔离级别。
你可以用下列语句设置全局和会话事务隔离级别:
mysql> set tx_isolation='read-committed'; --会话参数
mysql> set global tx_isolation='read-committed'; --全局参数
read-committed 读已提交
repeatable-read 可重复读
你可以用下列语句查询全局和会话事务隔离级别:
SELECT @@global.tx_isolation; --全局参数,等同于 show global variables like 'tx_isolation'
SELECT @@session.tx_isolation; --会话参数,等同于 show variables like 'tx_isolation' 或 SELECT @@tx_isolation;