如何保證數據庫讀寫事務


場景

先講下我當時遇到的一個應用場景:

一份含有5萬條數據的表,希望每次都能從中獲取到一條未被使用過的數據,然后再標記該條數據已被使用。

數據庫時mysql,為方便起見,轉化成sql的語義就是:

一張表:

value status
v1 1
v2 1
... 1

 

 

 

 

我們需要一次讀取一行數據,再把該行的status字段改成0。它必然涉及到一次select,一次update,那如何保證的事務呢?

特別說明:表結構並不是必須這樣,你可以自己設計。

 

解決思路

如果你覺得很簡單:直接select這條數據,然后update它即可。那就真的悲劇了。

比如說這樣的讀寫SQL

SELECT value FROM table WHERE status = 1 LIMIT 1
UPDATE table SET status = 0 WHERE value = 'v1'

如果每次請求都如下圖一樣,是依次順序執行,的確是沒有任何問題

但是如果應用的並發量很高時,這樣就會出現問題,比如下圖中,用戶2在用戶1執行完畢select但沒執行完畢update時,執行了select。那么用戶1和用戶2將獲得同一條數據,這明顯不是我們想要的結果。

那又什么好的解決方案呢?相信很多人立馬想到的方案肯定是事務。不錯,用事務的確是種不錯的解決方案

解決方案一:事務 

START TRANSACTION;
SELECT value FROM table WHERE status = 1 LIMIT 1
UPDATE table SET status = 0 WHERE value = 'v1'
COMMIT;或rollback;

 但畢竟事務是種很影響性能的方法, 那有沒有可以不用事務的方法呢?

解決方案二:根據UPDATE結果判定是否有效

依據的原理是,在Mysql中執行UPDATE語句時,它會返回執行結果,具體如下:

mysql> UPDATE table SET status = 0 WHERE value = 'v1' AND status = 1;
Query OK, 0 rows affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

這里 Rows matched 表示匹配的數量,Changed表示改動的行數

回到剛到的問題,我們可以用這些信息來判斷是否成功

SELECT value FROM table WHERE status = 1 LIMIT 1
UPDATE table SET status = 0 WHERE value = 'v1' AND status = 1

當返回結果是:

Rows matched: 1  Changed: 1  Warnings: 0

表示這次數據更新是有效的。

當返回結果是:

Rows matched: 0  Changed: 0  Warnings: 0

表示這次數據更新失敗,因為該行數據已經別人占用,需要重試

但這種方法的問題,就是並發量特別高時,很多請求會出現沖突,需要重試。

解決方案三:利用表的自增id屬性

id value status
1 v1 1
2 v2 1

 

 

 

id 是該表的自增主鍵(auto_increment)

需要另外一張表table2

id ...
1 ...
2 ...
... ...

 

 

 

 

id 也是該表的自增主鍵(auto_increment)

 

INSERT INTO table2 ( ....) VALUES( .... );
獲取到table2 中最近的id
UPDATE table SET status = 0 WHERE id = id
SELECT value FROM table WHERE id = id

 由於自增id是唯一性的,所以可以保證最終得到的數據也是唯一性的,但缺點也非常明顯:多需要一張表,而且兩張表的id需要一定的映射關系。

解決方案四:引入requestID字段

表設置為:

value status request_id
v1 1  
v2 1  

 

 

 

使用SQL:

UPDATE table SET status = 0, request_id = 'xxxxx'  WHERE status = 1 LIMIT 1
SELECT value FROM table WHERE request_id = 'xxxxx'

只要保證request_id是唯一性,我們得到的結構也肯定是有效的

 

希望對大家有所幫助。^v^

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM