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,可以参考这篇文章: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 表 WRITE
UNLOCK TABLE;
我们来测试一下,第一个进程执行
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
,就是这么简单!
以上内容由chenqionghe提供,别忘了点个赞哈~~
MySQL如何加锁控制并发的更多相关文章
- JAVA程序对MYSQL数据库加锁实验
什么是脏读,不可重复读,幻读 1. 脏读 :脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据. 2. 不可重 ...
- java并发编程学习:用 Semaphore (信号量)控制并发资源
并发编程这方面以前关注得比较少,恶补一下,推荐一个好的网站:并发编程网 - ifeve.com,上面全是各种大牛原创或编译的并发编程文章. 今天先来学习Semaphore(信号量),字面上看,根本不知 ...
- 使用mysql悲观锁解决并发问题
最近学习了一下数据库的悲观锁和乐观锁,根据自己的理解和网上参考资料总结如下: 悲观锁介绍(百科): 悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持 ...
- PHP通过加锁实现并发情况下抢码功能
本文基于php语言使用加锁实现并发情况下抢码功能,特定时间段开放抢码并不允许开放的码重复: 需求:抢码功能 要求: 1.特定时间段才开放抢码: 2.每个时间段放开的码是有限的: 3.每个码不允许重复: ...
- MySQL InnoDB 实现高并发原理
MySQL 原理篇 MySQL 索引机制 MySQL 体系结构及存储引擎 MySQL 语句执行过程详解 MySQL 执行计划详解 MySQL InnoDB 缓冲池 MySQL InnoDB 事务 My ...
- Nodejs - 如何用 eventproxy 模块控制并发
本文目标 本文的目标是获取 ZOJ 1001-1010 每道题 best solution 的作者 id,取得数据后一次性输出在控制台. 前文 如何用 Nodejs 分析一个简单页面 我们讲了如何用 ...
- Java--Semaphore控制并发线程数量
package com; import java.util.concurrent.Semaphore; /** * Created by yangyu on 16/11/28. */ /** * Se ...
- entity framework如何控制并发
entity framework如何控制并发 针对字段http://msdn.microsoft.com/en-us/library/vstudio/bb738618(v=vs.100).aspx ...
- Database(Mysql)发版控制二
author:skate time:2014/08/18 Database(Mysql)发版控制 The Liquibase Tool related Database 一.Installation ...
随机推荐
- 说说在 Python 中如何快速复制序列
1 基本用法 把序列乘以一个整数,就会产生一个新序列.这个新序列是原始序列复制了整数份,然后再拼接起来的结果. l=[1,2,3] l2=l * 3 logging.info('l2 -> %s ...
- 在python中元组与列表的区别及序列解包
一. 元组与列表的区别 元组中的数据一旦定义就不允许更改. 元组没有append().extend()和insert()等方法,无法向元组中添加元素. 元组没有remove()或pop()方法,也无法 ...
- js Table表格选中一行变色或者多选 并获取值
使用JQ <script> let old, oldColor; $("#sp_body tr").click(function (i) { if (old) oldC ...
- JAVA 实体类List<Entity >转 List<Map>
public static <T extends IdEntity> List<Map<Object,Object>> EntityConvertMap(List& ...
- lock与synchronized 的区别【网上收集】
1. 区别 类别 synchronized Lock 存在层次 Java的关键字,在jvm层面上 是一个接口 锁的释放 1.以获取锁的线程执行完同步代码,释放锁 2.线程执行发生异常,jvm会让线程释 ...
- ceph对接k8s storage class
简介 对接ceph的rbd和cephfs到k8s中提供持久化存储 环境 主机名 IP role 操作系统 ceph-01 172.16.31.11 mon osd CentOS7.8 ceph-02 ...
- vue-cli3 创建项目路由缺失问题
1.在项目中新建一个router.js router.js import Vue from 'vue' import Router from 'vue-router' import Home from ...
- 如何下载youtube的视频?
导言 当youtube视频需要下载时,发现需要会员等其他限制 别急,下面就是比较稳定的方法 准备 gitub链接 youtube-dl github 官网链接 官网 按照官网提示下载对应版本 我这里是 ...
- Mybatis-plus的使用步骤
Mybatis-plus的简单使用步骤 花开堪折直需折,莫待无花空折枝 导入依赖 <dependency> <groupId>org.projectlombok</gro ...
- IdentityServer4 之 Resource Owner Password Credentials 其实有点尴尬
前言 接着IdentityServer4的授权模式继续聊,这篇来说说 Resource Owner Password Credentials授权模式,这种模式在实际应用场景中使用的并不多,只怪其太开放 ...