日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MySQL 在高并发下的 订单撮合 系统使用 共享锁 与 排他锁 保证数据一致性

發(fā)布時(shí)間:2025/3/17 数据库 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL 在高并发下的 订单撮合 系统使用 共享锁 与 排他锁 保证数据一致性 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
原文:MySQL 在高并發(fā)下的 訂單撮合 系統(tǒng)使用 共享鎖 與 排他鎖 保證數(shù)據(jù)一致性

作者:林冠宏 / 指尖下的幽靈

掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8

博客:http://www.cnblogs.com/linguanh/

GitHub : https://github.com/af913337456/

騰訊云專欄: https://cloud.tencent.com/developer/user/1148436/activities

蟲洞區(qū)塊鏈專欄:https://www.chongdongshequ.com/article/1536563643883.html


前序

距離上次擇文發(fā)表,兩月余久。2018年也即將要結(jié)束了,目前的工作依然是與區(qū)塊鏈應(yīng)用相關(guān)的,也很榮幸在9月初受邀簽約出版暫名為《區(qū)塊鏈以太坊DApp實(shí)戰(zhàn)開發(fā)》一書,預(yù)計(jì)在明年年初出版。

這次讓我有感記錄這篇文章的原因是最近在使用Go語言重寫一個(gè)原來由PHP語言編寫的交易所訂單撮合模塊的時(shí)候,發(fā)現(xiàn)訂單撮合的部分代碼在撮合的時(shí)候,為保證各表數(shù)據(jù)在并發(fā)情況下不出現(xiàn)讀寫臟亂而采用了全局鎖表的操作。后面我采用了共享鎖的形式進(jìn)行了修改,于剛剛重寫完,并進(jìn)行了并發(fā)單元測(cè)試,表現(xiàn)正常。

目錄

  • 場(chǎng)景描述
  • 解決問題
  • 訂單撮合實(shí)例
  • 共享鎖 與 排他鎖
    • 前置知識(shí)
    • 行鎖與表鎖
    • 兩種行鎖的特點(diǎn)
    • 兩種行鎖的加鎖方式
    • 鎖的釋放
    • 操作例子
  • 改造代碼片段

場(chǎng)景描述

高并發(fā)的業(yè)務(wù)常見是有很多種類的,最常見的例如秒殺搶購。它們都有一個(gè)共同的特點(diǎn)就是數(shù)據(jù)更新都比較頻繁,通常涉及到多張業(yè)務(wù)表的增改操作,且表格越多的,要考慮的問題也越多。

訂單撮合可以理解為訂單買賣,拿這個(gè)為例子進(jìn)行列舉一個(gè)可能會(huì)導(dǎo)致數(shù)據(jù)錯(cuò)亂的情形。假設(shè)現(xiàn)在買賣手機(jī),A用戶是要買手機(jī)的,B用戶是賣手機(jī)的。A的買入單訂單1,和B的賣出單訂單2,訂單2賣出手機(jī),一臺(tái)手機(jī)賣1000元。此時(shí)A的網(wǎng)上的錢包余額是1001元,剛好比手機(jī)價(jià)格高,是可以成交的。

此時(shí)記錄用戶錢包錢數(shù)數(shù)量的是一張數(shù)據(jù)表。每次花費(fèi)了錢或者增加了錢,都要更新這個(gè)表。

當(dāng)這兩筆訂單進(jìn)入到系統(tǒng)里面進(jìn)行撮合。假設(shè)系統(tǒng)的訂單撮合運(yùn)行流程如下圖所示:

當(dāng)判斷條件進(jìn)行A用戶的錢包余額判斷的時(shí)候,發(fā)現(xiàn) 1001 > 1000,結(jié)果是通過,此時(shí)準(zhǔn)備進(jìn)入“進(jìn)行記錄更細(xì)”步驟。但是,就在這個(gè)過程之中的時(shí)間差中,A用戶使用了系統(tǒng)的網(wǎng)上提現(xiàn)功能,并成功轉(zhuǎn)出了10元,剩余的是1001 - 10 = 991元。但是由于撮合系統(tǒng)的余額判斷過程以及通過了,導(dǎo)致下面的交易流程依然能進(jìn)行,最終A用991元買了B的1000元售價(jià)的手機(jī)。

解決問題

上述的常見問題是一個(gè)很簡單的模型,現(xiàn)實(shí)的系統(tǒng)中往往是更復(fù)雜的。但是它所體現(xiàn)出的問題卻是真實(shí)存在的,對(duì)于這類問題,有很多解決方案。其中,就可以考慮使用數(shù)據(jù)庫的鎖。

本文要介紹的是MySQL數(shù)據(jù)庫的共享鎖 與 排他鎖,其它的不作說明或引申。

訂單撮合實(shí)例

下面的截圖就是我所重寫好的撮合系統(tǒng)原始的PHP代碼,所使用了表鎖的方式來解決前面的并發(fā)讀寫導(dǎo)致數(shù)據(jù)臟亂的問題。這種方式雖然是解決了問題,但是導(dǎo)致了性能低下的問題。

共享鎖 與 排他鎖

前置知識(shí):

  • MySQL 是數(shù)據(jù)庫,不是數(shù)據(jù)庫引擎
  • MySQL有兩種常用存儲(chǔ)引擎: MyISAM和InnoDB
  • MyISAM不支持事務(wù)操作,InnoDB支持事務(wù)操作
  • MySQL 的鎖分有 行鎖 和 表鎖
  • MyISAM 只有表鎖
  • Innodb 行鎖,表鎖都有
  • 行鎖中有共享鎖和排他鎖
  • 共享鎖 簡稱 S鎖,排他鎖簡稱 X鎖

行鎖與表鎖

簡述:

  • 行鎖,鎖的是表中對(duì)應(yīng)的行,只限制當(dāng)前行的讀寫。

  • 表鎖,鎖的是整張表,限制的是整張表的數(shù)據(jù)讀寫。

比較:

  • 行鎖,計(jì)算機(jī)資源開銷大,加鎖慢;會(huì)出現(xiàn)死鎖;鎖定粒度最小,鎖沖突的概率最低,并發(fā)度最高,性能高。
  • 表鎖,計(jì)算機(jī)資源開銷小,加鎖快;不會(huì)出現(xiàn)死鎖;鎖定粒度大,鎖沖突的概率最高,并發(fā)度最低,性能低。

兩種行鎖的特點(diǎn)

共享鎖

A 對(duì)數(shù)據(jù) B 加了 共享鎖,A能讀取和修改數(shù)據(jù)B,C 等其它只能讀取數(shù)據(jù)B,但是不能修改。直至A釋放了B的鎖。

排他鎖

A 對(duì)數(shù)據(jù) B 加了 排他鎖,A能讀取和修改數(shù)據(jù)B,C 等其它不能再對(duì)數(shù)據(jù)B加其它的鎖。直觀體驗(yàn)是不能修改,不能使用含有加鎖動(dòng)作的select讀取。

兩種行鎖的加鎖方式

要注意的是:

  • 行鎖的實(shí)現(xiàn)SQL語句中必須要有索引的限制條件,例如含有 where id=xxx 這類語句。
  • 行鎖的實(shí)現(xiàn)SQL語句沒有索引限制條件會(huì)變成表鎖
  • InnoDB引擎 默認(rèn)的修改數(shù)據(jù)類SQL語句,update,delete,insert等,都會(huì)自動(dòng)給涉及到的數(shù)據(jù)加上排他鎖。

共享鎖

  • select 的添加可以使用滿足格式:select ... where 索引限制 lock in share mode 的語句。例如“select name from lgh_user where id = 1 lock in share model” 此時(shí) id 是索引。

排他鎖

  • 滿足格式:select ... where 索引限制 for update 的語句

鎖的釋放

  • 非事務(wù)(Transaction) 中,語句執(zhí)行完畢,便釋放鎖。

  • 行鎖在事務(wù) (Transaction) 中,只有等到當(dāng)前的事務(wù)Transaction 進(jìn)行了 commit 或 roll back,鎖才能釋放。

操作例子

演示事務(wù) tx 中的例子,文字解析見圖。

改造代碼片段

撮合中的所有表鎖替換成了共享鎖,運(yùn)行其它業(yè)務(wù)讀取所鎖的行數(shù)據(jù),在當(dāng)前事務(wù)的批量操作還沒結(jié)束之前,不允許修改。

總結(jié)

以上是生活随笔為你收集整理的MySQL 在高并发下的 订单撮合 系统使用 共享锁 与 排他锁 保证数据一致性的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。