前篇
tidb在3.0.8之後預設開啟悲觀事務,但是autocommit 事務優先采用樂觀事務送出,翻譯一下這句話就是,如果是不手動開啟事務的場景,同時兩個insert/update語句還是走的樂觀鎖機制,就有機率觸發
write conflict
觸發方式如圖:
先
SET @@tidb_txn_mode = '';
調整本次會話為樂觀模式

解決 write conflict
write conflict
有兩個辦法
1:在預設悲觀事務的情況下開啟事務(有點繞,說的再簡單點就是java要加上
@Transactional
注解)
2:開啟樂觀事務重試機制,并重建立立tidb連接配接(建立立的連接配接才會用上新參數)
SET GLOBAL tidb_disable_txn_auto_retry = OFF;
SET GLOBAL tidb_retry_limit = 10;
第一點很好了解,問題出在于第二點,因為官方原話為
TiDB 預設不進行事務重試,因為重試事務可能會導緻更新丢失,進而破壞可重複讀的隔離級别。
當事務中存在依賴查詢結果來更新的語句時,重試将無法保證事務原本可重複讀的隔離級别,最終可能導緻結果與預期出現不一緻。
這兩句話其實很難了解,讓我們來看下圖的例子
例子1
同樣要先
SET @@tidb_txn_mode = '';
調整本次會話為樂觀模式,然後開啟重試機制
最後結果也就是t6的更新其實并沒有成功,因為實際這個時候的id=1資料已經被session B更新為了status=0,在重試的時候自然比對不上更新條件.然後我們再回過頭來看官方的原話,因為重試事務可能會導緻更新丢失.但是這個真的是更新丢失嗎,我們回想下在如果以上操作在mysql下的場景,在t6這一步的時候,mysql會觸發目前讀,然後直接告訴你0 row affectied(忘記截圖了,可以自己試下),那麼在t9這個時間的時候,mysql和tidb的表象其實是一緻的,差別在于中間更新的時候傳回的影響行數
例子2
讓我們再來看一個例子
| | | | | -- | ---------------------------------------------------------- | ---------------------------------------- | | | session a | session b | | t1 |
begin
| | | t2 | |
begin
| | t3 |
update tidb set status =0 where id = 1
| | | t4 | |
update tidb set status =1 where id = 1
| | t5 | |
commit
| | t6 |
commit
| | | t7 |
SELECT * from tidb where id = 1
id name status 1 tidb 0 | |
可以看出在這個例子裡,update資料的時間不重要,commit的時間才重要,後面commit的資料會把先commit的資料進行覆寫,對于mysql來說,在t4這一步就會被阻斷,直到session a送出事務,是以在這個場景下,tidb和mysql是完全不一樣的
總結下
1.可能會造成傳回的更新條數與實際情況不同,但是最終表象會和mysql一緻
2.自然時間的更新順序将沒有參考意義,資料的最新記錄與commit時間有關,這一點和mysql不一緻
幻讀
再額外說下幻讀
可以先看下這個文章看下mysql的幻讀
https://www.wolai.com/jtaGKJqoUusS5mmA5NqoG1
由于tidb沒有間隙鎖
是以再這個場景下,tidb的表象也和mysql不一緻
| | | | | -- | ------------------------------------------- | ------------------------------------------------------------- | | | session a | session b | | t1 |
begin;
| | | t2 | |
begin;
| | t3 |
SELECT * from tidb where id >3 for UPDATE
| | | | | | | t4 | |
INSERT INTO tidb (id, name, status) VALUES (12, 'tidb', 7);
| | t5 | |
commit;
| | t6 |
SELECT * from tidb where id >3 for UPDATE
| | | | | | | | 可以查詢到insert的資料 | |
在mysql的場景下,在t4這一步就會被阻塞,直到t3加的鎖被釋放
其他參考文章
TiDB和MySQL的鎖一些分析比對 技術文章
【是否原創】是 【首發管道】TiDB 社群 【首發管道連結】其他平台首發請附上對應連結 【正文】 [image] 圖1 鎖分類圖 一、悲觀鎖和樂觀鎖 TiDB一開始是樂觀鎖,但自TiDB3.0版本開始,支援悲觀事務,并且在3.0.8版本開始預設使用悲觀事務,支援悲觀鎖,檢視事務:show variables like ‘%tidb_txn_mode%’; [image] 悲觀鎖的…