草庐IT

select ... for update学习

难顶货 2023-09-27 原文

文章目录

   无意见看到关于select … for update的推送,突然发现自己以前没见过,故学习记录下,大概浏览了以下,主要是涉及锁的问题。开始前,先复习两个概念,悲观锁和乐观锁。

悲观锁和乐观锁

   乐观锁和悲观锁只是两个加锁的思路,其实现方式多种多样。以下举几个在数据库中的例子。
  对于一次的数据修改,我们可以大概将其分为三步。

  • 获取数据
  • 修改数据
  • 提交修改

  这里假设A、B两个角色对数据进行修改。

乐观锁

   乐观锁对数据保持一个乐观态度(大概率不会有人和我抢)。A角色获取数据、修改数据时不会对数据加锁,只有在提交修改时才会判断中间是否有其他人对数据进行了修改。(因为没有对数据加锁,B角色可在A角色获取数据后,也获取到数据,甚至比A提前提交数据修改)。

   一个简单的实现就是给数据添加版本号字段(此处命名为version),例如A角色在获取数据阶段,获取到的版本号为V1,则在提交修改阶段的执行语句就为

update .......where version = V1

   这样当数据在中途被B角色修改后,version字段将不为原来的V1,此条更新语句也就失效了。不会导致数据更新异常。

悲观锁

   悲观锁对数据保持一个悲观态度(绝逼会有人来和我抢),则在角色A获取数据后,就对数据进行了加锁,直到修改数据、提交修改后才将锁释放。中途由于数据已经被加锁,角色B压根读不数据,也就不存在中途被修改的情况。

select … for update

  回到正题,我们平时使用的select语句只是查询,不涉及修改,故不存在加锁的概念。而select * for update 从字面意思就可以知道,该语句不单单是查询,而是为了后续的修改,所以是要对数据加锁的,并且是悲观锁。此时按照select 中where条件字段,又可分为行锁和表锁。
在这里我们新建一个数据库来讨论,雇员表,销售部14人,技术部10人,共24人。(在这里留意以下人数比例。后面这个比例会影响查询)。建表语句放在帖子最后。

where 主键字段

当查询用到索引时是行锁。

  我们在会话1中采用主键来查询一条信息,可正常显示结果。由于没有执行rollback,该事务没有退出,此时该条数据被行锁。

  我们新建一个会话2同样通过主键查询主键为111和112的数据。此时由于会话1行锁了数据111,会导致会话2中的查询111被阻塞。而会话2查询112可正常查出。

where普通字段

当查询用没用到索引时是表锁。
  我们在会话1中采用普通字段来查询一条信息,可正常显示结果。由于没有执行rollback,该事务没有退出,此时表表被表锁。

  我们在会话2中采用普通字段来查询一条信息,发现无论使用什么来查询,均被阻塞。

进阶

  当我们使用非索引字段进行select … for update 时,会造成表锁。此时我们尝试将该非索引字段设置为索引。
  将dname设置为索引后,在会话1中执行查询dname = ‘销售部’

  会得出结果,在会话2中我们查询销售部的员工,发现阻塞。查询非销售部的员工,可出结果。成功将表锁转化为了行锁。

  此时我们调整表中的部门,使得数据大部分为销售部

  这个时候在和上面一样做相同查询,会发现,除了销售部数据被锁定外,技术部数据也被锁定。变成了表锁。

  原因是当索引列中,所查的值占绝大部分时,会走全索引扫描,相当与将该字段看成普通字段来操作,故会形成表锁。

用到的sql

CREATE TABLE `employee` (
  `empno` int(11) NOT NULL,
  `ename` varchar(255) DEFAULT NULL,
  `job` varchar(255) DEFAULT NULL,
  `hiredate` datetime DEFAULT NULL,
  `sal` varchar(255) DEFAULT NULL,
  `dname` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`empno`),
  KEY `dname_index` (`dname`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (111, '销售1', '销售', '2022-08-20 16:14:18', '800', '销售部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (112, '销售2', '销售', '2022-08-20 16:14:12', '80012', '销售部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (113, '销售3', '销售', '2022-08-20 16:14:13', '80013', '销售部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (114, '销售4', '销售', '2022-08-20 16:14:14', '80014', '销售部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (115, '销售5', '销售', '2022-08-20 16:14:15', '80015', '销售部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (116, '销售6', '销售', '2022-08-20 16:14:16', '80016', '销售部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (117, '销售7', '销售', '2022-08-20 16:14:17', '80017', '销售部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (118, '销售8', '销售', '2022-08-20 16:14:18', '80018', '销售部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (119, '销售9', '销售', '2022-08-20 16:14:19', '80019', '销售部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (120, '销售10', '销售', '2022-08-20 16:14:20', '80020', '销售部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (121, '销售11', '销售', '2022-08-20 16:14:21', '80021', '销售部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (122, '销售12', '销售', '2022-08-20 16:14:22', '80022', '销售部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (123, '销售13', '销售', '2022-08-20 16:14:23', '80023', '销售部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (124, '销售14', '销售', '2022-08-20 16:14:24', '80024', '销售部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (125, '技术1', '技术', '2022-08-20 16:14:25', '80025', '技术部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (126, '技术2', '技术', '2022-08-20 16:14:26', '80026', '技术部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (127, '技术3', '技术', '2022-08-20 16:14:27', '80027', '技术部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (128, '技术4', '技术', '2022-08-20 16:14:28', '80028', '技术部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (129, '技术5', '技术', '2022-08-20 16:14:29', '80029', '技术部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (130, '技术6', '技术', '2022-08-20 16:14:30', '80030', '技术部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (131, '技术7', '技术', '2022-08-20 16:14:31', '80031', '技术部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (132, '技术8', '技术', '2022-08-20 16:14:32', '80032', '技术部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (133, '技术9', '技术', '2022-08-20 16:14:33', '80033', '技术部');
INSERT INTO `test`.`employee` (`empno`, `ename`, `job`, `hiredate`, `sal`, `dname`) VALUES (134, '技术10', '技术', '2022-08-20 16:14:34', '80034', '技术部');

参考

【【IT老齐201】小心select for update,有效规避索引选择性锁表】 https://www.bilibili.com/video/BV1YU4y1C7j4?share_source=copy_web&vd_source=bf91fef3a99fcdb25f54a2281be92cf0

有关select ... for update学习的更多相关文章

  1. ruby-on-rails - rspec should have_select ('cars' , :options => ['volvo' , 'saab' ] 不工作 - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request

  2. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  3. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  4. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  5. ruby-on-rails - 事件记录 : Select max of limit - 2

    我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).

  6. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

  7. ruby-on-rails - rails 上的 ruby : radio buttons for collection select - 2

    我有一个集合选择:此方法的单选按钮是什么?谢谢 最佳答案 Rails3中没有这样的助手。在Rails4中,它是collection_radio_buttons. 关于ruby-on-rails-rails上的ruby:radiobuttonsforcollectionselect,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/18525986/

  8. ruby - 我如何学习 ruby​​ 的正则表达式? - 2

    如何学习ruby​​的正则表达式?(对于假人) 最佳答案 http://www.rubular.com/在Ruby中使用正则表达式时是一个很棒的工具,因为它可以立即将结果可视化。 关于ruby-我如何学习ruby​​的正则表达式?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1881231/

  9. ruby - Rails 3 - 我可以将开始日期设置为 date_select 方法吗? - 2

    date_select方法只能设置:start_year,但我想设置开始日期(例如3个月前的日期)(但没有这样的选项)。那么,我可以将开始日期设置为date_select方法吗?或者,要制作这样的选择框,我应该使用select_tag和options_for_select吗?或者,有什么解决办法吗?谢谢, 最佳答案 有可能……例如:start_year–设置年份选择的开始年份。默认为Time.now.year-5参见thisresource. 关于ruby-Rails3-我可以将开始日期

  10. 深度学习12. CNN经典网络 VGG16 - 2

    深度学习12.CNN经典网络VGG16一、简介1.VGG来源2.VGG分类3.不同模型的参数数量4.3x3卷积核的好处5.关于学习率调度6.批归一化二、VGG16层分析1.层划分2.参数展开过程图解3.参数传递示例4.VGG16各层参数数量三、代码分析1.VGG16模型定义2.训练3.测试一、简介1.VGG来源VGG(VisualGeometryGroup)是一个视觉几何组在2014年提出的深度卷积神经网络架构。VGG在2014年ImageNet图像分类竞赛亚军,定位竞赛冠军;VGG网络采用连续的小卷积核(3x3)和池化层构建深度神经网络,网络深度可以达到16层或19层,其中VGG16和VGG

随机推荐