MYSQL事务避免脏读、不可重复读、幻读

事务具有ACID四种特性。

但是Isolation并发可能引起如下问题:

1.脏读

允许读取到未提交的脏数据。

2.不可重复读

如果你在时间点T1读取了一些记录,在T2时再想重新读取一次同样的这些记录时,这些记录可能已经被改变、或者消失不见。

3.幻读

解决了不重复读,保证了同一个事务里,查询的结果都是事务开始时的状态(一致性)。但是,如果另一个事务同时提交了新数据,本事务再更新时,就会“惊奇的”发现了这些新数据,貌似之前读到的数据是“鬼影”一样的幻觉。

由ANSI/ISO定义的SQL-92标准定义的四种隔离级别

1.Read Uncommitted

2.Read Committed

3.Repeatable Read

4.Serializable


隔离解别 脏读 不可重复读 幻读
Read Uncommitted Y Y Y
Read Committed N Y Y
Repeatable(default) N N Y
Serializable N N N


mysql> select @@global.tx_isolation,@@tx_isolation;
+-----------------------+-----------------+
| @@global.tx_isolation | @@tx_isolation  |
+-----------------------+-----------------+
| REPEATABLE-READ       | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.00 sec)

更改隔离级别为完全串行化 Serializable 后,不存在幻读的问题。


mysql> set global tx_isolation='serializable';
Query OK, 0 rows affected (0.00 sec)

mysql> set session tx_isolation='serializable';
Query OK, 0 rows affected (0.00 sec)

在这种情况下,只允许一个事务在执行,其它事务必须等待这个事务执行完后才能执行。没有并发,只是单纯的串行。

这里要注意一个问题,就是需要串行化的事务,必须在事务开始第一句用UPDATE操作一下。这样其他串行化事务操作才会被锁住,必须等上个事务释放。

比如:

事务A:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> update a set xx=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0


事务B:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> update a set xx=1;
Query OK, 0 rows affected (38.73 sec)
Rows matched: 1  Changed: 0  Warnings: 0


这里事务B必须等事务A执行完后,才会执行。(第一句必须是UPDATE或INSERT,并且是同一张表,如果都是SELECT语句则不会锁住)

如果事务第一句是SELECT的话,则会出现这样结果

事务A,SELECT发现可执行

事务B,SELECT发现也可执行

结果:两个事务都执行了同样的操作,并不是我们想要的逻辑。


常用语句:

start transaction;
	select * from a;
	insert into a (uid) values(1);
	update a set xx=1;
rollback;
commit;


select @@global.tx_isolation,@@tx_isolation;
set global tx_isolation='serializable';
set session tx_isolation='serializable';  



你可能感兴趣的:(mysql)