數據庫並發的問題


並發操作會帶來一系列的問題

  1. 更新丟失(lost update)

    當兩個或多個事務選擇了同一行然后基於最初選定的值更新改行時,由於每個事務都不知道其他事務的存在,就會發生丟失更新的問題,最后更新覆蓋了由其他事務所做的更新

  2. 臟讀 (Dirty reads)

    一個事務正在對一條記錄做修改,在這個事務完成並提交前,這條記錄的數據就處於不一致的狀態;這時,另一個事務也讀取同一條基礎,如果不加控制,第二個事務讀取這些"臟"數據,並據此作進一步的處理,就會產生未提交的數據的依賴關系,這種叫做"臟讀"

  3. 不可重復讀(Non-Repeatable reads)

    一個事務在讀取某些數據的某個時間,再次讀取以前讀過的數據,卻發現其讀出的數據已經發生改變,或者某些記錄被刪除了!! 這就叫不可重復讀

    (不符合隔離性)

  4. 幻讀

    一個事務按相同的查詢條件讀取以前檢索過的數據,卻發現其他事務插入了滿足其查詢條件的新數據,這種現象叫做"幻讀",好像重來沒出現過

     

    設置了 mysql 事務隔離級別, mysql對於操作同一行數據會自動加鎖

     

     

    對於可重復讀, mysql使用的是 MVCC 機制 ,multi version concurrent control,多版本並發控制機制

    select 操作不會更新版本,每次查詢都會做一次快照,用的是快照版本。然后修改后,真實數據以及和快照版本不一致了,但是 mysql為了讓邏輯准確,更新的時候會那數據庫最新的數據進行更新,而讀是讀的快照版本的數據。

    商品超賣,就是這種原因。

     

    https://blog.csdn.net/huaishu/article/details/89924250

    這種就是當前讀和快照讀的區別

    快照讀會讓性能高一點。所以 select 出來再 update 會有 bug

    注意點:sql應該這樣寫: update account set balance = balance-50 where id = 1;

     

     

     

     

    可重復讀的話,select不會更新版本好,是快照讀(歷史版本),而insert 、update和delete 會更新版本好,是當前讀(當前版本)

    所以更新之后再開查就可能會有幻讀的現象:

     

    session1: select * from account;

    session2: insert into account (name,money) values('ss',100);

    session1: update account set name = 'lyr' where id = 1 ;

    session1: select * from account;

     

    如果 session1: 沒有update account 這張表,會用快照讀,不會出現幻讀的問題

    然而: session1: update 了 account這張表,那么就會從快照讀改當前讀

    而session2 這個時候 插入了一條 name='ss', money=100 的數據

    session1 再來查表,發現無緣無故有多了一條,這個就像幻覺一樣的數據(幽靈般的出現了)

    這個就是幻讀

     

    改成 串行化,那就什么問題也沒有了,但是不應該這樣,因為效率低

    mysql 使用可重復讀 兼顧了效率盡量的解決了臟讀和不可重復讀的問題

     

     

    查看mysql近期死鎖的日志信息:

    show engine innodb status\G

     

     

    mysql的優化:

    1. 盡可能讓所有數據檢索通過索引完成,避免無索引行鎖升級為表鎖
    2. 合理設計索引,盡量縮小鎖的范圍
    3. 盡可能檢索檢索條件,避免間隙鎖
    4. 盡量控制事務大小,減少鎖定資源量和時間長度
    5. 盡可能低級別的事務隔離

這樣就可以解決並發問題了

  1. update account set money = money-1 where id='llyr' and money >0;

 

mysql可以使用一個間隙鎖,只要是范圍的話 mysql自動加鎖,一般不會有幻讀問題

 

條件 是一個范圍,mysql就加鎖了

這樣可以解決幻讀問題

https://blog.csdn.net/spring_model/article/details/53992450

還有其他的鎖,比如 for update 獨占鎖之類的

 

mysql 開啟事務的時候 update語句的時候加鎖,COMMIT后釋放

所以sql 寫的好,一般不會有問題。

 

 


免責聲明!

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



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