在服务开发中使用意向锁

举报
码乐 发表于 2025/02/02 09:44:40 2025/02/02
【摘要】 1 简介意向锁的设计模式意向锁(Intention Locks)是一种表级锁,用于指示事务即将在表中的某些行上加锁。它的主要作用是提高并发控制效率,防止锁冲突,同时允许不同粒度的锁共存。意向锁本质上是一种表级别的锁,表示事务打算对表中某些行进行锁定,它并不会阻塞其他事务的意向锁,而是与表级别的共享锁(S锁)或排他锁(X锁)互斥。 2. 意向锁的分类在 MySQL(InnoDB)中,意向锁有...

1 简介

  • 意向锁的设计模式

意向锁(Intention Locks)是一种表级锁,用于指示事务即将在表中的某些行上加锁。

它的主要作用是提高并发控制效率,防止锁冲突,同时允许不同粒度的锁共存。

意向锁本质上是一种表级别的锁,表示事务打算对表中某些行进行锁定,它并不会阻塞其他事务的意向锁,而是与表级别的共享锁(S锁)或排他锁(X锁)互斥。

2. 意向锁的分类

在 MySQL(InnoDB)中,意向锁有以下几种类型:

意向共享锁(IS,Intention Shared)
事务打算在表中某些行上加共享锁(S 锁),需要先在表级别加 IS 锁。

意向排他锁(IX,Intention Exclusive)
事务打算在表中某些行上加排他锁(X 锁),需要先在表级别加 IX 锁。

意向锁的冲突规则

        锁类型 IS  IX  S   X
        IS  兼容  兼容  兼容  冲突
        IX  兼容  兼容  冲突  冲突
        S   兼容  冲突  兼容  冲突
        X   冲突  冲突  冲突  冲突

说明:

IS/IX 之间不会互相冲突,提高了并发性。
IX 不能和 S 兼容,因为 S 需要保证整个表可读,而 IX 可能会引入 X 锁。
X 锁与任何锁都不兼容。

3. 意向锁的使用场景

意向锁适用于高并发数据库环境下,尤其是在行级锁(Record Lock)和表级锁(Table Lock)同时存在的情况下。它的主要作用如下:

避免表级锁的冲突:如果一个事务已经在某些行上持有锁,意向锁可以防止另一个事务直接对整个表加锁,从而避免长时间的锁等待。

提高锁管理效率:数据库可以通过意向锁快速判断是否可以安全地加表级锁,而不需要遍历所有行锁。
支持细粒度并发控制:允许多个事务在不同的行上持有排他锁,而不影响表级锁的管理。

4. MySQL 数据库中的意向锁示例

假设有一张 users 表:

        CREATE TABLE users (
            id INT PRIMARY KEY AUTO_INCREMENT,
            name VARCHAR(100),
            balance DECIMAL(10,2)
        ) ENGINE=InnoDB;

(1)事务 1 在 users 表的某一行上加排他锁

        START TRANSACTION;
        SELECT * FROM users WHERE id = 1 FOR UPDATE;

这里 FOR UPDATE 会在 id=1 的记录上加行级排他锁(X 锁)。
MySQL 会自动在 users 表上加意向排他锁(IX 锁)。

(2)事务 2 尝试对 users 表加共享锁

        START TRANSACTION;
        LOCK TABLE users READ;

由于事务 1 持有行级排他锁(X 锁),并且意向排他锁(IX 锁)阻止了共享锁(S 锁),事务 2 必须等待事务 1 释放锁。

5. 服务中使用意向锁

这是一个高性能的 Go 语言 Web 框架,通常用于构建 RESTful API。结合 MySQL 使用意向锁的场景,假设我们实现一个简单的银行转账 API,在转账时使用意向锁保证数据一致性。

示例:银行转账 API

        var db *sql.DB

        func init() {
            var err error
            dsn := "root:password@tcp(127.0.0.1:3306)/testdb?parseTime=true"
            db, err = sql.Open("mysql", dsn)
            if err != nil {
                log.Fatal(err)
            }
            db.SetMaxOpenConns(10)
            db.SetMaxIdleConns(5)
        }

        // 处理转账
        func transfer(c *gin.Context) {
            fromID := c.Query("from")
            toID := c.Query("to")
            amount := c.Query("amount")

            tx, err := db.Begin()
            if err != nil {
                c.JSON(http.StatusInternalServerError, gin.H{"error": "事务开启失败"})
                return
            }

            // 使用 FOR UPDATE 确保余额不会被并发修改
            _, err = tx.Exec("SELECT balance FROM users WHERE id = ? FOR UPDATE", fromID)
            if err != nil {
                tx.Rollback()
                c.JSON(http.StatusInternalServerError, gin.H{"error": "查询账户失败"})
                return
            }

            _, err = tx.Exec("SELECT balance FROM users WHERE id = ? FOR UPDATE", toID)
            if err != nil {
                tx.Rollback()
                c.JSON(http.StatusInternalServerError, gin.H{"error": "查询账户失败"})
                return
            }

            // 进行转账操作
            _, err = tx.Exec("UPDATE users SET balance = balance - ? WHERE id = ?", amount, fromID)
            if err != nil {
                tx.Rollback()
                c.JSON(http.StatusInternalServerError, gin.H{"error": "扣款失败"})
                return
            }

            _, err = tx.Exec("UPDATE users SET balance = balance + ? WHERE id = ?", amount, toID)
            if err != nil {
                tx.Rollback()
                c.JSON(http.StatusInternalServerError, gin.H{"error": "存款失败"})
                return
            }

            err = tx.Commit()
            if err != nil {
                c.JSON(http.StatusInternalServerError, gin.H{"error": "事务提交失败"})
                return
            }

            c.JSON(http.StatusOK, gin.H{"message": "转账成功"})
        }

        func main() {
            r := gin.Default()
            r.POST("/transfer", transfer)
            r.Run(":8080")
        }

6. 结论

意向锁主要用于表级锁管理,提高并发控制效率。
MySQL 会自动管理意向锁,不需要手动设置。

在服务中,使用 FOR UPDATE 可以触发意向锁,防止并发问题。

实际开发中,事务处理需要注意死锁问题,适当调整索引、事务顺序来优化并发。
这样,我们可以安全地在高并发环境下实现数据库的锁管理,避免数据不一致问题。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。