MySQL樂觀鎖和悲觀鎖的使用與區(qū)別
MySQL 中的樂觀鎖和悲觀鎖是兩種不同的并發(fā)控制策略,它們各有特點(diǎn)和適用場(chǎng)景。
一、悲觀鎖(Pessimistic Locking)
概念
悲觀鎖假設(shè)數(shù)據(jù)沖突經(jīng)常發(fā)生,因此在操作數(shù)據(jù)之前先獲取鎖,確保在事務(wù)期間數(shù)據(jù)不會(huì)被其他事務(wù)修改。
實(shí)現(xiàn)方式
使用數(shù)據(jù)庫(kù)內(nèi)置的鎖機(jī)制:
-- 1. 開始事務(wù) START TRANSACTION; -- 2. 加排他鎖(悲觀鎖) SELECT * FROM products WHERE id = 1 FOR UPDATE; -- 3. 執(zhí)行業(yè)務(wù)邏輯 UPDATE products SET stock = stock - 1 WHERE id = 1; -- 4. 提交事務(wù) COMMIT;
特點(diǎn)
- 思想:先加鎖,后操作
- 實(shí)現(xiàn):依賴數(shù)據(jù)庫(kù)鎖機(jī)制(行鎖、表鎖等)
- 適用場(chǎng)景:
- 寫操作頻繁的場(chǎng)景
- 數(shù)據(jù)競(jìng)爭(zhēng)激烈的環(huán)境
- 需要強(qiáng)一致性的業(yè)務(wù)
優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
- 保證強(qiáng)一致性
- 實(shí)現(xiàn)簡(jiǎn)單,直接使用數(shù)據(jù)庫(kù)功能
- 適合高并發(fā)寫場(chǎng)景
缺點(diǎn):
- 性能開銷大(加鎖、釋放鎖)
- 可能產(chǎn)生死鎖
- 降低系統(tǒng)并發(fā)度
二、樂觀鎖(Optimistic Locking)
概念
樂觀鎖假設(shè)數(shù)據(jù)沖突很少發(fā)生,因此不加鎖直接操作,只在提交時(shí)檢查數(shù)據(jù)是否被修改過(guò)。
實(shí)現(xiàn)方式
通常使用版本號(hào)或時(shí)間戳:
方法1:版本號(hào)機(jī)制
-- 表結(jié)構(gòu)增加版本字段
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(100),
stock INT,
version INT DEFAULT 0
);
-- 更新時(shí)檢查版本號(hào)
UPDATE products
SET stock = stock - 1, version = version + 1
WHERE id = 1 AND version = 1; -- 這里的1是讀取時(shí)的版本號(hào)
-- 檢查影響行數(shù),如果為0表示版本不一致,需要重試
方法2:時(shí)間戳機(jī)制
-- 表結(jié)構(gòu)增加時(shí)間戳字段
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(100),
stock INT,
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- 更新時(shí)檢查時(shí)間戳
UPDATE products
SET stock = stock - 1
WHERE id = 1 AND update_time = '2024-01-01 10:00:00';
方法3:條件判斷(基于業(yè)務(wù)字段)
-- 基于庫(kù)存數(shù)量判斷 UPDATE products SET stock = stock - 1 WHERE id = 1 AND stock > 0;
重試機(jī)制
由于樂觀鎖可能失敗,通常需要配合重試邏輯:
// Java 示例代碼
public boolean deductStockWithRetry(int productId, int quantity) {
for (int i = 0; i < MAX_RETRY; i++) {
Product product = productDao.getById(productId);
if (product.getStock() < quantity) {
return false; // 庫(kù)存不足
}
int affectedRows = productDao.updateStock(productId, quantity, product.getVersion());
if (affectedRows > 0) {
return true; // 更新成功
}
// 版本沖突,重試
Thread.sleep(100); // 短暫等待
}
throw new RuntimeException("更新失敗,超過(guò)最大重試次數(shù)");
}特點(diǎn)
- 思想:先操作,提交時(shí)檢查
- 實(shí)現(xiàn):基于應(yīng)用層邏輯(版本號(hào)、時(shí)間戳等)
- 適用場(chǎng)景:
- 讀多寫少的場(chǎng)景
- 數(shù)據(jù)沖突較少的業(yè)務(wù)
- 對(duì)性能要求高的系統(tǒng)
優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
- 提高系統(tǒng)并發(fā)性能
- 避免死鎖問題
- 減少數(shù)據(jù)庫(kù)鎖開銷
缺點(diǎn):
- 實(shí)現(xiàn)相對(duì)復(fù)雜
- 需要處理更新失敗的情況
- 不適合高并發(fā)寫場(chǎng)景
三、對(duì)比總結(jié)
| 特性 | 悲觀鎖 | 樂觀鎖 |
|---|---|---|
| 思想 | 先加鎖后操作 | 先操作后檢查 |
| 實(shí)現(xiàn)方式 | 數(shù)據(jù)庫(kù)鎖機(jī)制 | 版本號(hào)/時(shí)間戳 |
| 性能 | 并發(fā)度低,開銷大 | 并發(fā)度高,開銷小 |
| 適用場(chǎng)景 | 寫多讀少,沖突頻繁 | 讀多寫少,沖突較少 |
| 一致性 | 強(qiáng)一致性 | 最終一致性 |
| 死鎖風(fēng)險(xiǎn) | 有 | 無(wú) |
| 實(shí)現(xiàn)復(fù)雜度 | 簡(jiǎn)單 | 相對(duì)復(fù)雜 |
四、實(shí)際應(yīng)用建議
選擇悲觀鎖的場(chǎng)景
- 銀行轉(zhuǎn)賬、庫(kù)存扣減等金融業(yè)務(wù)
- 需要強(qiáng)一致性的核心業(yè)務(wù)
- 寫操作非常頻繁的系統(tǒng)
選擇樂觀鎖的場(chǎng)景
- 商品瀏覽、社交媒體的點(diǎn)贊功能
- 讀多寫少的業(yè)務(wù)系統(tǒng)
- 對(duì)性能要求較高的互聯(lián)網(wǎng)應(yīng)用
混合使用策略
在實(shí)際項(xiàng)目中,可以根據(jù)不同業(yè)務(wù)場(chǎng)景混合使用:
-- 核心業(yè)務(wù)使用悲觀鎖 START TRANSACTION; SELECT * FROM account WHERE user_id = 123 FOR UPDATE; -- 執(zhí)行資金操作 COMMIT; -- 非核心業(yè)務(wù)使用樂觀鎖 UPDATE article SET like_count = like_count + 1 WHERE id = 456 AND version = current_version;
五、注意事項(xiàng)
- 悲觀鎖要合理設(shè)置事務(wù)隔離級(jí)別和鎖等待超時(shí)時(shí)間
- 樂觀鎖要設(shè)計(jì)合理的重試策略和重試次數(shù)上限
- 在高并發(fā)場(chǎng)景下,樂觀鎖的重試可能造成"驚群效應(yīng)"
- 根據(jù)業(yè)務(wù)特點(diǎn)選擇合適的鎖策略,不要一概而論
這兩種鎖策略各有優(yōu)劣,關(guān)鍵在于根據(jù)具體的業(yè)務(wù)場(chǎng)景和性能要求來(lái)選擇最合適的方案。
到此這篇關(guān)于MySQL樂觀鎖和悲觀鎖的使用的文章就介紹到這了,更多相關(guān)MySQL樂觀鎖和悲觀鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mysql數(shù)據(jù)庫(kù)鎖定機(jī)制詳細(xì)介紹
這篇文章主要介紹了Mysql數(shù)據(jù)庫(kù)鎖定機(jī)制詳細(xì)介紹,本文用大量?jī)?nèi)容講解了Mysql中的鎖定機(jī)制,例如MySQL鎖定機(jī)制簡(jiǎn)介、合理利用鎖機(jī)制優(yōu)化MySQL等內(nèi)容,需要的朋友可以參考下2014-12-12
查看本地MYSQL數(shù)據(jù)庫(kù)IP地址的三種方法
本文介紹了多種方法來(lái)查看連接到本地MySQL服務(wù)器的IP地址,括使用SQL查詢從`information_schema.processlist`獲取IP地址,并通過(guò)`group by`進(jìn)行統(tǒng)計(jì),以及通過(guò)命令行工具如`mysql`和`awk`進(jìn)行過(guò)濾和計(jì)數(shù),這些方法有助于監(jiān)控和管理數(shù)據(jù)庫(kù)連接,需要的朋友可以參考下2024-10-10
Ubuntu18.04 安裝mysql8.0.11的圖文教程
本文通過(guò)圖文并茂的形式給大家介紹了Ubuntu18.04 安裝mysql8.0.11的方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的的朋友參考下吧2018-07-07
MySQL的執(zhí)行原理之 MySQL的查詢重寫規(guī)則詳解
MySQL 性能調(diào)優(yōu)是一個(gè)復(fù)雜且多維度的過(guò)程,下面從數(shù)據(jù)庫(kù)設(shè)計(jì)、查詢優(yōu)化、配置參數(shù)調(diào)整、硬件優(yōu)化幾個(gè)方面為你介紹相關(guān)的調(diào)優(yōu)方法,本文給大家介紹MySQL的執(zhí)行原理之 MySQL的查詢重寫規(guī)則,感興趣的朋友一起看看吧2025-04-04
MySQL?根據(jù)表名稱生成完整select語(yǔ)句詳情
這篇文章主要介紹了MySQL?根據(jù)表名稱生成完整select語(yǔ)句,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06

