MYSQL 事务隔离级别
MYSQL INNODB事务的隔离级别有四级, 默认是 可重复读(repeatable read)。
1. 未提交读(read uncommitted). 另一个事务修改了数据, 但沿未提交, 而本事务中的SELECT会读到这些未提交的数据(脏读).
2. 提交读(READ COMMITTED). 本事务读取到的是最新的数据(其他事务提交后的). 问题是, 在同一个事务里, 前后两次相同的SELECT会读到不同的结果(不重复读)。
3. 可重复读(REPEATABLE READ)。 在同一个事务里, SELECT的结果是事务开始时时间点的状态, 因此,同样的SELECT操作读到的结果会是一致的, 但是会有幻读现象。
4. 串行化(SERIALIZABLE)。 读操作会隐式获取共享锁,可以保证不同事务间的互斥。
四个级别逐渐增强, 每个级别解决一个问题:
脏读: 最容易理解。 另一个事务修改了数据,但沿未提交,而本事务中的SELECT会读到这些未被提交的数据。
不重复读:解决了脏读后, 会遇到, 同一个事务执行过程中,另外一个事务提交了新数据, 因此本事务先后两次读到的数据结果也不一致。
幻读:解决了不重复读,保证了同一个事务里, 查询的结果都是事务开始时的状态(一致性)。 但是,如果另一个事务同时提交了新数据, 本事务再更新时, 就会发现了这些新数据,貌似之前读到的数据是影子一样的幻觉。
关于幻读的小测试:
测试一: CREATE TABLE `t_bitfly` ( `id` bigint(20) NOT NULL default '0', `value` varchar(32) default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB; select @@global.tx_isolation, @@tx_isolation; mysql> select @@global.tx_isolation, @@tx_isolation; +-----------------------+-----------------+ | @@global.tx_isolation | @@tx_isolation | +-----------------------+-----------------+ | REPEATABLE-READ | REPEATABLE-READ | +-----------------------+-----------------+ 1 row in set (0.00 sec) 会话一: mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t_bitfly; Empty set (0.00 sec) 会话二: mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO t_bitfly values(1,'a'); Query OK, 1 row affected (0.01 sec) 在这里不提交,去会话一上去查询。 mysql> SELECT * FROM t_bitfly; Empty set (0.07 sec) 还是空的, 如果这时我去会话二上把事务提交了呢 mysql> commit; Query OK, 0 rows affected (0.01 sec) 再去会话一上去查看。 mysql> SELECT * FROM t_bitfly; Empty set (0.00 sec) 还是没有, 这就把可重复读体现出来了, 如果是CR的隔离级别,在这里就可以看到刚提交的数据了。 下面我们再去会话一上执行一个插入的SQL。 查询出来是空的, 但为何插入就报错了呢, 这就是幻读。