暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL数据库——版本号机制和CAS(Compare And Swap)

编程Cookbook 2025-03-11
14

大家好,这里是编程Cookbook。本文详细介绍乐观锁的两种实现方式:版本号机制和CAS(Compare And Swap)。


目录

  • MySQL 内置的并发控制机制
    • MVCC(多版本并发控制)
    • 锁机制
    • 总结
  • 乐观锁实现方式(需要手动实现)
    • 1. 版本号机制
    • 2. CAS(Compare And Swap)
    • 3. 版本号机制 vs CAS

MySQL 内置的并发控制机制

MySQL 内置了强大的并发控制机制,例如 MVCC(多版本并发控制) 和锁机制。这些机制在更高层次上实现了并发控制。自动处理事务隔离和并发冲突,适用于复杂数据库事务管理。

MVCC(多版本并发控制)

  • 核心:基于事务 ID 和 Undo Log,实现高效的读写并发。
  • 特点:快照读无需加锁,写操作使用回滚日志实现隔离性。

MVCC的详细信息参考:《MySQL数据库——多版本并发控制MVCC》

锁机制

  1. 按锁粒度表锁行锁(InnoDB 默认)。

  2. 按锁类型共享锁(S 锁)排他锁(X 锁)

  3. 意向锁:用于标记表中是否有行级锁,避免加锁冲突。

  4. 按加锁机制分:悲观锁和乐观锁。

    • 悲观锁:通过显式加锁防止并发冲突。
    • 乐观锁:通过版本号机制和CAS实现,本文重点

锁的详细信息参考:《MySQL数据库——锁的分类》

总结

版本号机制、CAS和MVCC 的实现方式在不同层面有区别。以下是对它们在 程序员实现  MySQL 内部支持 上的区别详细分析:

机制程序员实现MySQL 支持
版本号机制
程序员设计表结构,手动添加 version
字段和条件更新
MySQL 不直接支持,由程序员通过 SQL 手动实现
CAS
程序员通过 SQL 条件更新模拟类似行为
MySQL 不支持硬件级 CAS,仅能通过条件更新实现
MVCC
程序员无需手动实现
MySQL 内置支持,通过事务 ID 和 Undo Log 实现
  • 程序员实现的版本号机制和 CAS
    • 需要手动设计表结构、编写 SQL。
    • 适用于轻量级业务逻辑的并发控制。

乐观锁实现方式(需要手动实现)

版本号机制  CAS(Compare And Swap) 是实现 乐观锁 的两种常见方式,它们的核心思想是通过条件检查来保证并发安全。以下是两种方法的实现详细介绍:


1. 版本号机制

MySQL 本身并未内置对 版本号机制 的直接支持。版本号机制通常由应用程序开发人员在数据库设计和操作层手动实现

基本原理

  • 为每一条记录添加一个额外的字段版本号)。
  • 在更新数据时,先检查版本号是否与读取时一致,再执行更新。
  • 版本号的变化表明数据已经被其他事务修改,当前事务需要重新尝试或放弃。

实现步骤

  1. 读取数据和版本号

    SELECT versionvalue FROM table_name WHERE id = 1;

    复制
    • 查询需要更新的记录,并获取当前版本号。
  2. 检查版本号并更新

    UPDATE table_name
    SET value = 'new_value'version = version + 1
    WHERE id = 1 AND version = 10;

    复制
    • 在更新时,检查版本号是否一致。
    • 如果一致,执行更新并将版本号加 1。
  3. 处理并发冲突(如果存在)

    • 如果 WHERE
       子句中的 version
       不匹配,说明该记录已被其他事务修改,当前事务更新失败。

示例

假设表结构如下:

CREATE TABLE table_name (
    id INT PRIMARY KEY,
    value VARCHAR(255),
    version INT
);

复制

事务 A:

SELECT versionvalue FROM table_name WHERE id = 1-- 返回 version = 10
UPDATE table_name SET value = 'new_value'version = version + 1 WHERE id = 1 AND version = 10;

复制

事务 B(同时运行):

SELECT versionvalue FROM table_name WHERE id = 1-- 返回 version = 10
UPDATE table_name SET value = 'another_value'version = version + 1 WHERE id = 1 AND version = 10-- 更新失败

复制

优缺点

  • 优点
    • 不需要加锁,性能高。
    • 简单易实现。
  • 缺点
    • 需要额外的字段存储版本号。
    • 并发冲突时,需要重试或回滚,可能增加系统开销。

2. CAS(Compare And Swap)

MySQL 不直接支持类似硬件级别的 CAS 操作。对于类似 CAS 的功能,依赖程序员通过代码实现【也有说通过 SQL 实现】。

基本原理

  • CAS 是一种原子操作,用于更新某个值时,先比较当前值是否符合预期。
  • 如果当前值符合预期,则执行更新,否则不更新。

实现步骤

  1. 读取数据的当前值

    • 获取目标变量的当前值。
  2. 比较值是否符合预期

    • 如果当前值与预期值一致,说明没有其他线程修改过该值。
  3. 更新数据

    • 在当前值符合预期时,执行更新。
    • 如果值不一致,操作失败,可以选择重试。

示例:Go 中 CAS 实现

Go 中的 CAS 使用 sync/atomic
 包提供的 CompareAndSwap
 系列方法。

package main

import (
"fmt"
"sync/atomic"
)

func main() {
var counter int32 = 10

// 期望值是 10,新值是 11
 success := atomic.CompareAndSwapInt32(&counter, 1011)

if success {
  fmt.Printf("Update successful, new value: %d\n", counter)
 } else {
  fmt.Printf("Update failed, current value: %d\n", counter)
 }
}


复制

补充:也有说可以通过SQL实现,SQL实现,本质上和版本号机制一样,不一样的点在于不需要额外字段,直接操作数据值(count
)。如下:

-- 假设表结构如下:
CREATE TABLE counter (
    id INT PRIMARY KEY,
    count INT );

-- 当前 count = 10 
UPDATE counter SET count = count + 1 WHERE id = 1 AND count = 10

复制

优缺点

  • 优点
    • 无需加锁,性能高。
    • 操作是原子的,由硬件保证一致性。
  • 缺点
    • 存在 ABA 问题(值从 A 改为 B,又改回 A,CAS 不会察觉)。
    • 如果冲突频繁,可能导致多次重试。

3. 版本号机制 vs CAS

特性版本号机制CAS
实现方式基于字段的版本号
,依赖 SQL 条件更新或程序逻辑
基于硬件支持的原子操作,直接比较并更新
字段要求
需要额外的版本号字段(version
不需要额外字段
,直接操作数据值
适用场景
数据库或程序语言中的并发控制
程序语言中的并发控制,数据库中可通过条件更新模拟
是否依赖数据库
通常依赖 SQL 实现,但也可在程序中实现
不依赖数据库
,可直接通过程序实现
优点
简单易用,适合数据库复杂业务场景
高性能,无需锁,硬件原子操作支持
缺点
存在重试开销,版本号字段增加存储开销
存在 ABA 问题,冲突频繁时重试代价较高

两者适用于不同的场景,但核心思想相同:通过比较条件,确保操作的正确性。


文章转载自编程Cookbook,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论