可重復讀
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'。