關於update操做併發問題

在高併發的場景下,常常會遇到這種狀況:
A請求過來,查詢出來一條數據,進行update操做,與此同時B請求也在這個時候過來,對這條數據進行查詢,並進行操做。此時就會出現B在A以後進行查詢操做,可是實際B的數據卻被A覆蓋。mysql

表名A,字段名爲 number,以下的SQL語句:sql

甲操做 語句1:select num from store where id='1';數據庫

假設此時甲獲取到 num= 99併發

乙操做 語句2:select num from store where id='1';ide

由於甲方尚未update操做,乙獲也取到 num= 99
這時候A進行update操做高併發

update store set num =${num} +1 where id='1';事務

這時候寫入數據庫的num即爲100
此時B請求也發起了更新操做:it

update store set num =${num} +1 where id='1';io

這時候咱們的預期本應該是101的,可是實際上B又在數據庫寫入了100class

解決方案:

(1)引入一個版本號的概念,在表A中增長一個version字段

甲操做 語句1:select num,version from store where id='1';

假設此時甲獲取到 num= 99 version =1

乙操做 語句2:select num,version from store where id='1';

由於甲方尚未update操做,乙獲也取到 num= 99 version=1
這時候A進行update操做

update store set num =${num} +1 where id='1' and version = ${version};

這時候寫入數據庫的num即爲100, version =2
此時B請求也發起了更新操做:

update store set num =${num} +1 where id='1' and version = ${version} ;

這時候發現條件version = 1不成立,由於上一步操做version已經爲2了,因此update沒法更新。

(2)解決方式:update A set number=number+1 where id=1; 語句直接處理

表名A,字段名爲 number,以下的SQL語句:

語句1:update A set number=number+1 where id=1;
語句2:update A set number=number+2 where id=1;

假設這兩條SQL語句同時被mysql執行,id=1的記錄中number字段的原始值爲99,那麼是否有可能出現這種狀況:
語句1和2由於同時執行,他們獲得的number的值都是99,都是在10的基礎上分別加1和2,致使最終number被更新爲100或101,而不是102

這個其實就是 關係型數據庫自己就須要解決的問題。首先,他們同時被MySQL執行,你的意思其實就是他們是併發執行的,而併發執行的事務在關係型數據庫中是有專門的理論支持的- ACID,事務並行等理論,全部關係型數據庫實現,包括Oracle, MySQL都須要遵循這個原理。簡單一點理解就是鎖的原理。這個時候第一個update會持有id=1這行記錄的 排它鎖,第二個update須要持有這個記錄的排它鎖的才能對他進行修改,正常的話, 第二個update會阻塞,直到第一個update提交成功,他纔會得到這個鎖,從而對數據進行修改。也就是說,按照關係型數據庫的理論,這兩個update都成功的話,id=1的number必定會被修改爲22。若是不是22, 那就是數據庫實現的一個嚴重的bug。

相關文章
相關標籤/搜索