导读

Hi,大家好!我是白日梦!本文是MySQL专题的第 27 篇。

下文还是白日梦以自导自演的方式,围绕“如何实现记录存在的话就更新,如果记录不存在的话就插入。”展开本话题。看看你能抗到第几问吧

换一种写作风格,自导自演面试现场!感觉这样还是比较有趣的,欢迎大家订阅我的MySQL专题,公众号首发!持续更新中~

点击阅读原文,有视频串讲、视频实战各种案例、格式也会好看一点哦~

点击阅读原文,有视频串讲、视频实战各种案例、格式也会好看一点哦~

点击阅读原文,有视频串讲、视频实战各种案例、格式也会好看一点哦~

欢迎关注白日梦,公众号首发!持续连载中

推荐阅读原文,可以看视频教程!

推荐阅读原文,可以看视频教程!

推荐阅读原文,可以看视频教程!




那我们继续,还是这道场景题:现在我的业务中有这样的需求:如果目标记录存在的话我就更新它,如果记录不存在的话我就插入。说说看你知道哪些实现方式吧!



嗯,比如我可以像下面这样做






这种方式。

// 伪代码user=User.FindById(1)if user == null{  user.Insert()}else{  user.Update()}








嗯!你这段代码如果不存在并发访问还好,一旦出现并发访问的情况。你这段逻辑会有诸多的并发修改异常的!





比如这样的例子:商品有上线和下线的状态,然后管理员可以在后台页面中修改商品的状态,比如代码这样写的:

// 伪代码,如果将状态置反if product.Status == “online”{   product.Status = "offline";}else{   product.Status = "online";  }





这时管理员A、B并发的去操作商品状态:



嗯,确实存在这种情况,不过我可以自定义FindById()中的sql语句,通过 select for update的方式,规避你在图画出来的风险。






比如自定义SQL,让 user = User.FindByID(1)函数执行的SQL为

select * from user where id = 1 for update;

直接select时会给id = 1的行添加一把读锁,现在我通过select for update检索,在读select时给id = 的行添加写锁。

那么当我在读取使用这行数据时,其他的人select for update

就会被阻塞,因为写锁之间彼此是互



斥的。最终也不会出现Update彼此覆盖的情况









哦?那你画一个时序图出来瞧瞧



嗯嗯,时序图大概长下面这样









嗯,乍一看你上面画的这个图是没问题的,但我有个问题:如果id = xx的行不存在呢?






嗯,所以我们不如分不同情况讨论一下。下面我列举不同场景,你画时序图怎样?



嗯嗯,好的!









嗯!首先我们知道了,select for update会尝试添加X锁,也就是写锁。

常见的写锁有这么几种:

1、record lock 给指定行记录添加锁

2、gap lock 间隙锁

3、next key lock

下面通过在不同条件下执行select for update sql,再观察实验结果,就能八九不离十的推测出for update的加锁情况。






实验一已知条件如下:

create table t(a int,b int,primary key(a),key(b));insert into t select 1,1;insert into t select 3,1;insert into t select 5,3;insert into t select 7,6;insert into t select 10,8;

select for update sql为:

select * from t where a= 5 for update;

提示:注意id=5的行已经存在了。

下面你画一下时序图吧



嗯嗯,时序图加锁情况如下:









嗯,那如果我们需要执行的sql如下:

select * from t where b = 3 for update;

注意b并不是唯一键,它只是一个普通索引哦!

你能画一下它的加锁时序图吗?



嗯嗯,时序图如下:

(最后一条Sql条件是 where a = 5,不是a=3)









还是使用这些数据

create table t(a int,b int,primary key(a),key(b));insert into t select 1,1;insert into t select 3,1;insert into t select 5,3;insert into t select 7,6;insert into t select 10,8;

假如我执行的sql是:

select * from t where a = 13 for update;

注意:

1、a=13的行并不存在哦!

2、a是唯一索引

你画一下它的时序图吧!





嗯呢,时序图如下:









还是使用这些数据

create table t(a int,b int,primary key(a),key(b));insert into t select 1,1;insert into t select 3,1;insert into t select 5,3;insert into t select 7,6;insert into t select 10,8;

假如我执行的sql是:

select * from t where a = 8 for update;

注意:

1、a=8的行并不存在哦!

2、a是唯一索引

你画一下它的时序图吧!



嗯嗯、如下:

对唯一索引来说,gap的上下都锁不住!









还是使用这些数据

create table t(a int,b int,primary key(a),key(b));insert into t select 1,1;insert into t select 3,1;insert into t select 5,3;insert into t select 7,6;insert into t select 10,8;

假如我执行的sql是:

select * from t where b = 5 for update;

注意:

1、b=5的行并不存在哦!

2、b是普通索引

你画一下它的时序图吧!



嗯嗯、如下。

对普通索引来说,gap锁会 锁上不锁下!









嗯,对的。回到我们一开始的主题:如果数据存在我们就update

数据不存在我们就insert的话题来看的话。

通过如下方案:

begin;select for update;# insert or update;commit;

是可以保证并发修改的安全性的....



嗯嗯、其实通过实验来看,确实是安全的。









小伙子可以的!整体感觉还不错。

欢迎关注我。不久会给你安排下一面

我没有问题了,你有什么想问我的吗?



暂时没有了,感谢大佬






视频+图文串讲:MySQL 行锁、间隙锁、Next-Key-Lock、以及实现记录存在的话就更新,如果记录不存在的话就插入如何保证并发安全的更多相关文章

  1. 死锁问题分析(个人认为重点讲到了gap间隙锁,解决了我一些不明报死锁的问题)

    线上某服务时不时报出如下异常(大约一天二十多次):“Deadlock found when trying to get lock;”. Oh, My God! 是死锁问题.尽管报错不多,对性能目前看来 ...

  2. (10)MySQL进阶篇SQL优化(InnoDB锁-间隙锁)

    1.概述 当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁:对于键值在条件范围内但并不存在的记录,叫做"间隙(GAP)&quo ...

  3. 【Mysql】表锁 行锁 记录锁 间隙锁

    Mysql中的锁 基于锁的属性分类:共享锁.排他锁. 基于锁的状态分类:意向共享锁.意向排它锁 根据锁的粒度分类:全局锁.页锁.表级锁.行锁(记录锁.间隙锁.和临键锁),实际上的锁就这些,上面两种分类 ...

  4. mysql 隔离级别与间隙锁等

    数据库隔离级 SQL标准中DB隔离级别有: read uncommitted:可以读到其它transaction 未提交数据 read committed:可以读到其它transaction 已提交数 ...

  5. Mysql加锁过程详解(9)-innodb下的记录锁,间隙锁,next-key锁

    Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...

  6. Mysql 间隙锁原理,以及Repeatable Read隔离级别下可以防止幻读原理(百度)

    Mysql知识实在太丰富了,前几天百度的面试官问我MySql在Repeatable Read下面是否会有幻读出现,我说按照事务的特性当然会有, 但是面试官却说 Mysql 在Repeatable Re ...

  7. 推荐:mysql锁 innodb下的记录锁,间隙锁,next-key锁

    你需要知道的 之前我们介绍了排他锁,其实innodb下的记录锁(也叫行锁),间隙锁,next-key锁统统属于排他锁. 行锁 记录锁其实很好理解,对表中的记录加锁,叫做记录锁,简称行锁. 生活中的间隙 ...

  8. mysql间隙锁

    什么是间隙锁(gap lock)? 间隙锁是一个在索引记录之间的间隙上的锁. 间隙锁的作用? 保证某个间隙内的数据在锁定情况下不会发生任何变化.比如我mysql默认隔离级别下的可重复读(RR). 当使 ...

  9. mysql幻读、MVCC、间隙锁、意向锁(IX\IS)

    IO即性能 顺序主键写性能很高,由于B+树的结构,主键如果是顺序的,则磁盘页的数据会按顺序填充,减少数据移动,随机主键则可能由于记录移动产生很多io 查询二级索引时,会再根据主键id获取数据页,产生一 ...

随机推荐

  1. CF 1400F x-prime Substrings 题解【AC自动机+DP】

    CF 1400F.x-prime Substrings 题意: 给定一个由\('1'\)到\('9'\)组成的字符串\(s\)和一个数\(x\),定义一个串为\(x-prime\)串,当且仅当这个串上 ...

  2. 【noi 2.6_687】Color Tunnels(DP)

    P.S.o(︶︿︶)o 唉~虽然这题方程不难,但题目长,代码长,我花了超过3小时!(>﹏<)悲伤辣么大~~~ 谨此题解惠及众人,hh. 题意:给定长度为M的一串颜色序列,和平面上的N个颜色 ...

  3. 后缀数组Da模板+注释 以及 dc3模板

    后缀数组Da模板: 1 /* 2 后缀数组倍增法Da板子 3 */ 4 #include <cstdlib> 5 #include <cstring> 6 #include & ...

  4. 2019-2020 ACM-ICPC Brazil Subregional Programming Contest Problem M Maratona Brasileira de Popcorn (二分)

    题意:有\(n\)袋爆米花,某个队伍有\(c\)个队员,每个队员每秒做多可以吃\(t\)粒爆米花,但一袋爆米花只能由一个队员吃完,并且一个队员只能吃连续的一袋或几袋,不能隔着吃某一袋,求将所有爆米花吃 ...

  5. Dubbo从入门到实践

    1 Dubbo出现的背景 随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进. 我们传统的网站结构为 ...

  6. 【转】分布式事务之——tcc-transaction分布式TCC型事务框架搭建与实战案例

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/73731363 一.背景 有一定分布式开发经验的朋友都知道,产品/项目/系统最初为了 ...

  7. Python 分析热卖年货,今年春节大家都在送啥?

    今年不知道有多少小伙伴留在原地过年,虽然今年过年不能回老家,但这个年也得过,也得买年货,给家人长辈送礼.于是我出于好奇心的想法利用爬虫获取某宝数据,并结合 Python 数据分析和第三方可视化平台来分 ...

  8. 深入了解typeof与instanceof的使用场景及注意事项

    JavaScript中的数据类型分为两类,undefined,number,boolean,string,symbol,bigint,null[1]组成的基础类型和Object.Function.Ar ...

  9. leetcode 22. 括号生成 dfs

    先思考符合要求的串是什么样子的 任意时刻,(数量大于),且最后(==)==n即可 考虑下一个加入string的字符时(或者)即可 dfs class Solution { public: vector ...

  10. npm/yarn查看当前使用源与设置其它源

    npm, yarn查看源和换源: npm config get registry // 查看npm当前镜像源 npm config set registry https://registry.npmj ...