mysql資料庫的隔離性
程式碼review的時候看到同事把業務鎖(insertDelete實現)和業務操作放在一個事務裡。
程式碼結構如下:
transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { bizLockRepoImpl.insert(biz_id,id);//其中biz_id是主鍵 xxxxx; xxxxx; xxxxx; ……………; bizLockRepoImpl.delete(biz_id,id);//其中biz_id是主鍵 });
頓感十分奇怪,這樣根據『事務隔離性』的原則,豈不是等於沒有做併發控制麼?於是,立馬安裝了個mysql進行驗證。實驗如下,注意時序性:
實驗一:
目的:
證明,雖然第一個事務還沒提交,但是如果其他事務裡的sql涉及到和執行中的事務有主鍵衝突或者update了相同行的時候,其他的事務也是不能正常提交的。
原因:在MVCC控制中,寫操作是『當前讀』,讀取記錄的最新版本。並且,讀取之後,還需要保證其他併發事務不能修改當前記錄,對讀取記錄加鎖。
步驟:
1. 開啟一個mysql終端:
2. 開啟另外一個mysql終端:
mysql> insert into biz_lock vaules(8,8,now(),now()); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
輸出insert語句,就掛住了。等待了一段時間之後(一直不要去commit第一個事務),報錯如上。『等鎖超時』。
結論:
雖然我們知道資料庫具有隔離性『定義:當多個使用者併發訪問資料庫時,比如操作同一張表時,資料庫為每一個使用者開啟的事務,不能被其他事務的操作所幹擾,多個併發事務之間要相互隔離。』。資料庫引擎在事務commit前,也是會進行一些保護(因為資料庫引擎是怎麼實現的還沒有去研究,先把表象說明白)。
實驗二:
目的,看看我們所理解的資料庫事務的『隔離性』.
1. 客戶端一:
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> insert into biz_lock values(9,9,now(),now()); Query OK, 1 row affected (0.00 sec) mysql> select * from biz_lock where biz_id = 9; +------+--------+---------------------+---------------------+ | id | biz_id | gmt_create | gmt_modified | +------+--------+---------------------+---------------------+ | 9 | 9 | 2018-01-09 19:36:47 | 2018-01-09 19:36:47 | +------+--------+---------------------+---------------------+ 1 row in set (0.00 sec)
在一個事務裡insert了一條記錄,在這個事務裡select是可以看到的。
2. 客戶端二:
mysql> select * from biz_lock where biz_id = 9;
Empty set (0.00 sec)
3. 客戶端一:
mysql> commit work;
Query OK, 0 rows affected (0.00 sec)
4. 客戶端二:
mysql> select * from biz_lock where biz_id = 9;
+------+--------+---------------------+---------------------+
| id | biz_id | gmt_create | gmt_modified |
+------+--------+---------------------+---------------------+
| 9 | 9 | 2018-01-09 19:36:47 | 2018-01-09 19:36:47 |
+------+--------+---------------------+---------------------+
1 row in set (0.00 sec)
結論:我們看到,在事務一提交前,如果我們在其他的客戶端(即其他事務裡)查詢是看不到事務一里還沒有commit的資料的。即我們討論的事務隔離性。