事务是一系列数据操作的过程。事务具有四个特征,分别足原子性(Atomicity )、一致性(Consistency )、隔离性(Isolation) 和持久性(Durability),简称为事务的ACID特性。
先了解几种场景的名词定义:
脏读(Drity Read):A事务更新了一份数据,但是未提交(commit),B事务此时读到了这份未提交的更新数据,称之为脏读。如果事务A不回滚,基本上也没什么问题,如果事务A回滚了,问题可能就会非常大。
不可重复读(Non-repeatable read):A事务在执行过程中,B事务对数据进行了修改或删除(已commit),导致A两次读取的数据不一致;重点在于update和delete(锁行即可解决)。
幻读(Phantom Read):A事务在执行过程中,B事务新增了符合A事务要查询的数据,导致A两次读取的数据不一致;重点在于insert(需要锁表解决)。
Mysql的四种隔离级别
隔离级别依次递增,通过select @@tx_isolation;
可显示当前的隔离级别。
Read Uncommitted(读未提交)
在该隔离级别,mysql允许脏读(Dirty Read),即可以读到其他事务没有提交(commit)的内容。
Read Committed(读已提交)
只能读到其他事务已经提交的内容,因此不会出现脏读,但是会出现可不重复读、幻读
Repeatable Read(可重读)
解决了脏读、不可重复读的问题,但是会有可能出现幻读。这是MySQL默认的事务隔离级别。
Serializable(可串行)
不同级别会造成的问题
更新,关于可重读级别下的幻读问题
今天我在v2ex上发现有人讨论幻读的问题,发现第三级别下,并不会出现幻读问题,来看看我的操作:
no. | session 1 | session 2 |
---|---|---|
1 | begin; | begin; |
2 | select * from test; // 三条记录 | |
3 | insert into test(content, title) values (2,2); | |
4 | commit; | |
5 | select * from test; // 依然三条记录 |
但是先不要慌,我们尝试一下update操作:
no. | session 1 | session 2 |
---|---|---|
6 | update test set content = ” where id = 4; // 显示成功了一条! | |
6 | select * from test; // 发现session1中插入的那条出来了,神奇不?! |
所以对于MySQL5.7和后续版本(8.0),如果只是select,已经跟不会出现幻读了,但是如果需要执行update等操作,那就要注意了。
关于事务的一些SQL操作
查询事务当前的隔离级别:
select @@tx_isolation;
/*
输出结果:
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
*/
设置事务隔离级别:
-- 设置事务隔离级别为 read committed,仅在本次会话中生效
set session transaction isolation level read committed;
或者可以修改 my.cnf 配置文件使其永久生效:
[mysqld]
transaction-isolation = REPEATABLE-READ