实践理解Mysql事务隔离级别之可重复读
可重复读
Mysql的事务隔离级别,默认是可重复读(repeatable-read)。
以下通过具体的sql操作去理解可重复读。
建表
CREATE DATABASE test;
USE test;
CREATE TABLE `t_order` (
`fid` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键,自增id',
`forder_id` varchar(35) NOT NULL COMMENT '订单号,唯一',
`fpay_status` varchar(15) DEFAULT '00' COMMENT '00:未支付,01:支付成功,02:支付失败,03:已下单,04:申请退款,05:退款成功,06:退款失败,10:订单关闭',
PRIMARY KEY (`fid`),
UNIQUE KEY `forder_id` (`forder_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='订单表';
SELECT * FROM t_order;
多个事务操作
如果使用的是navicat,可以新建两个"查询"窗口,模拟A、B两个事务。
1.在两个窗口,分别执行以下语句,开启事务:
BEGIN;
2.查询数据:
SELECT * FROM t_order WHERE forder_id='abc';
结果如下:
3.在A事务中,执行update语句,然后再次查询:
UPDATE t_order SET fpay_status='01' WHERE forder_id='abc' AND fpay_status='00';
SELECT * FROM t_order WHERE forder_id='abc';
结果如下:
在A事务中,执行update后,fpay_status变为'01'
4.在B事务中,查询数据,结果如下:
由于A事务还没有提交,在可重复读的事务隔离级别下,B事务中的数据还是初始的值'00'。
接着,在B事务中,执行update语句,如下:
UPDATE t_order SET fpay_status='01' WHERE forder_id='abc' AND fpay_status='00';
发现B事务会阻塞,原因是A事务执行update语句时加了行锁。
一段时间后,B事务会超时。
重新开启B事务:
BEGIN;
5.提交A事务:
COMMIT;
然后,在B事务中查询,结果如下:
发现B事务中的fpay_status还是初始的值'00',这是因为:
在可重复读的事务隔离级别下,读取的是快照数据,总是读取当前事务开始时的行数据版本。
6.提交B事务。
COMMIT;
然后再次查询:
提交事务后,查询到的就是最新的数据了,fpay_status为'01'。