MySQL 加锁控制并发的方法

 更新时间:2021年01月29日 11:53:32   作者:雪山飞猪  
这篇文章主要介绍了MySQL 加锁控制并发的方法,帮助大家更好的理解和使用MySQL,感兴趣的朋友可以了解下

前言

锁总体可以分为乐观锁和悲观锁,简单说,乐观锁用版本号控制,悲观锁用锁控制。

下面是待会要用来测试的数据

# 添加一个user表
CREATE TABLE `users` (
 `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
 `name` varchar(255) NOT NULL COMMENT '姓名',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
# 插入3条数据
INSERT INTO `users` (`id`, `name`)
VALUES
 (1, '雪山飞猪'),
 (2, 'chenqionghe'),
 (3, 'cqh');

查询结果如下:

一、乐观锁

核心原理是增加一个version的字段来控制。
举个场景,我们希望并发更新单行记录的时候的时候,只有一个进程更新成功,如下

UPDATE users SET name="雪山飞猪" WHERE id=3
UPDATE users SET name="chenqionghe" WHERE id=3

上面这两个sql最终都会更新成功,且以最后更新结果为主。

解决办法是添加一个version字段

添加version字段

ALTER TABLE users ADD `version` INT NOT NULL DEFAULT '0'

解决办法是添加一个version字段,每个更新时where条件都加上它,并且也更新它

UPDATE users SET name="雪山飞猪",version=version+1 WHERE id=3 AND version=0
UPDATE users SET name="chenqionghe",version=version+1 WHERE id=3 AND version=0

这次变成了只会更新成功一次,谁先抢到这条记录以谁为主,因为当前一个进程更新成功后版本号已经变化了,第二个进程找不到这条记录了。
这就是最简单的CAS机制。

二、悲观锁

其实类似Go语言里的Mutex和RwMutex读锁

读锁

也叫共享锁或S锁,当给数据表加上共享锁的时候,表就变成了只读模式。
我们可以锁全表,也可以锁全表或部分行,如下

全表锁(LOCK TABLE 表 READ)

语法如下

LOCK TABLE 表 READ
UNLOCK TABLE;

我们来测试一个,第一个进程执行

LOCK TABLE users READ;

第二个进程执行正常读

SELECT * FROM users WHERE id=1;

可以正常查询。我们再来执行一下更新

UPDATE users SET name="chenqionghe" WHERE id=1

出现了等待。

我们给第一个进程解锁

再看第二个进程,已经更新成功

行锁(SELECT ... LOCK IN SHARE MODE)

BEGIN;
SELECT * FROM users WHERE id IN (1,2) LOCK IN SHARE MODE
COMMIT;

必须配合事务使用,BEIN开始后,锁定的行,外部只能查询,不能更新

我们来测试一下,第一个进程执行

BEGIN;
SELECT * FROM users WHERE id IN (1,2) LOCK IN SHARE MODE

这里锁定了id为1和2的记录行。我们第二个进程执行更新

UPDATE users SET name="雪山飞猪" WHERE id=1

又一次出现了等待。
好,这时候我们将第一个进程的事务提交

COMMIT;

第二个进程更新成功了,如下

写锁

也排他锁、独占锁,理解成读和写都不行了,语法如下

全表锁(LOCK TABLE 表 WRITE)

LOCK TABLE users WRITE;

这时候已经锁定全表,我们再用另一个进程查询一下id为1的数据

SELECT * FROM users WHERE id=1

可以看到,查询已经发生了等待。
我们再将第一个进程解锁

UNLOCK TABLE

这时候,第二个进程立马查询成功

行锁(SELECT ... FOR UPDATE)

当我们对数据进行更新的时候(INSERT、DELETE、UPDATE)的时候,数据库会自动使用排它锁,防止其他事务操作该数据

BEGIN;
SELECT * FROM users WHERE id IN (1,2) LOCK IN SHARE MODE
COMMIT;

我们再来测试一下,第一个进程锁定id为1和2的记录

BEGIN;
SELECT * FROM users WHERE id IN (1,2) FOR UPDATE

注意:这时候事务没提交

我们先用第二个进程来更新id为3的记录(未被锁定)

UPDATE users SET name="chenqionghe" WHERE id=3

执行成功了。
我们再来更新一个id为1的记录

UPDATE users SET name="chenqionghe" WHERE id=1

发生了等待,说明已经被锁定了。
好,我们提交第一个进程的事务

COMMIT;

再去看第二个进程,已经更新成功

简单说乐观锁用version控制,悲观锁的表锁一般用不着,行的读锁用LOCK IN SHARE MODE,写锁用FRO UPDATE,就是这么简单!

以上就是MySQL 加锁控制并发的方法的详细内容,更多关于MySQL 加锁控制并发的资料请关注脚本之家其它相关文章!

相关文章

  • MySQL查询语法汇总

    MySQL查询语法汇总

    这篇文章主要介绍了MySQL查询语法的汇总,帮助大家更好的理解和学习mysql,感兴趣的朋友可以了解下
    2020-08-08
  • MySQL中表分区技术详细解析

    MySQL中表分区技术详细解析

    数据库分区是一种物理数据库设计技术。虽然分区技术可以实现很多效果,但其主要目的是为了在特定的SQL操作中减少数据读写的总量以缩减sql语句的响应时间,同时对于应用来说分区完全是透明的。
    2016-06-06
  • MySQL 加锁控制并发的方法

    MySQL 加锁控制并发的方法

    这篇文章主要介绍了MySQL 加锁控制并发的方法,帮助大家更好的理解和使用MySQL,感兴趣的朋友可以了解下
    2021-01-01
  • innodb_index_stats导入备份数据时报错表主键冲突的解决方法

    innodb_index_stats导入备份数据时报错表主键冲突的解决方法

    下面小编就为大家带来一篇innodb_index_stats导入备份数据时报错表主键冲突的解决方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-03-03
  • 解决mysql删除用户 bug的问题

    解决mysql删除用户 bug的问题

    这篇文章主要介绍了解决mysql删除用户 bug的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-03-03
  • MySql超长自动截断实例详解

    MySql超长自动截断实例详解

    这篇文章主要介绍了MySql超长自动截断实例详解的相关资料,这里通过实例来说明如何实现自动截断的功能,需要的朋友可以参考下
    2017-07-07
  • linux(Centos7)下安装mysql8.0.18的教程图解

    linux(Centos7)下安装mysql8.0.18的教程图解

    这篇文章主要介绍了linux(Centos7)安装mysql8.0.18的教程,本文图文并茂给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-11-11
  • 在Windows系统上使用压缩归档文件安装MySQL的步骤

    在Windows系统上使用压缩归档文件安装MySQL的步骤

    这篇文章主要介绍了在Windows系统上使用压缩归档文件安装MySQL的步骤,非常不错,具有一定的参考借鉴加载,需要的朋友可以参考下
    2018-06-06
  • mysql如何让自增id归0解决方案

    mysql如何让自增id归0解决方案

    数据库的Id自增越来越大,要让自增重新从1开始:那么就用下面的方法吧
    2012-11-11
  • Centos7系统下Mysql主从同步配置方案

    Centos7系统下Mysql主从同步配置方案

    这篇文章主要给大家介绍了关于Centos7系统下Mysql主从同步配置的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Mysql具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-09-09

最新评论