MySQL行锁和表锁的含义及区别

今天在开发测试时候出现了锁表,原因是因为我在本地开启了事务,代码中打了断点,然后测试同学测试时候出现了锁表,我去排查了问题,然后找到相关的资料了解下,

总结:原因的表没有加索引,所以走了全表扫描,这时候开启了事务,没有commit。这时候另一个人想写表,发现表被锁了,然后测试同学说mysql是行锁,mysql确实支持行锁,但是前提条件是要走索引,不然就锁表

一、前言

对于行锁和表锁的含义区别,在面试中应该是高频出现的,我们应该对MySQL中的锁有一个系统的认识,更详细的需要自行查阅资料,本篇为概括性的总结回答。

MySQL常用引擎有MyISAM和InnoDB,而InnoDB是mysql默认的引擎。MyISAM不支持行锁,而InnoDB支持行锁和表锁。

如何加锁?

MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此用户一般不需要直接用LOCK TABLE命令给MyISAM表显式加锁。

显式加锁:

上共享锁(读锁)的写法:lock in share mode,例如:

select  math from zje where math>60 lock in share mode;

上排它锁(写锁)的写法:for update,例如:

select math from zje where math >60 for update;

二、表锁

不会出现死锁,发生锁冲突几率高,并发低。

MyISAM引擎

MyISAM在执行查询语句(select)前,会自动给涉及的所有表加读锁,在执行增删改操作前,会自动给涉及的表加写锁。

MySQL的表级锁有两种模式:

  • 表共享读锁

  • 表独占写锁

读锁会阻塞写,写锁会阻塞读和写

  • 对MyISAM表的读操作,不会阻塞其它进程对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后,才会执行其它进程的写操作。

  • 对MyISAM表的写操作,会阻塞其它进程对同一表的读和写操作,只有当写锁释放后,才会执行其它进程的读写操作。

MyISAM不适合做写为主表的引擎,因为写锁后,其它线程不能做任何操作,大量的更新会使查询很难得到锁,从而造成永远阻塞

三、行锁

会出现死锁,发生锁冲突几率低,并发高。

在MySQL的InnoDB引擎支持行锁,与Oracle不同,MySQL的行锁是通过索引加载的,也就是说,行锁是加在索引响应的行上的,要是对应的SQL语句没有走索引,则会全表扫描,行锁则无法实现,取而代之的是表锁,此时其它事务无法对当前表进行更新或插入操作。

CREATE TABLE `user` (`name` VARCHAR(32) DEFAULT NULL,`count` INT(11) DEFAULT NULL,`id` INT(11) NOT NULL AUTO_INCREMENT,PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8-- 这里,我们建一个user表,主键为id-- A通过主键执行插入操作,但事务未提交
update user set count=10 where id=1;
-- B在此时也执行更新操作
update user set count=10 where id=2;
-- 由于是通过主键选中的,为行级锁,A和B操作的不是同一行,B执行的操作是可以执行的-- A通过name执行插入操作,但事务未提交
update user set count=10 where name='xxx';
-- B在此时也执行更新操作
update user set count=10 where id=2;

-- 由于是通过非主键或索引选中的,升级为为表级锁,-- B则无法对该表进行更新或插入操作,只有当A提交事务后,B才会成功执行

for update

如果在一条select语句后加上for update,则查询到的数据会被加上一条排它锁,其它事务可以读取,但不能进行更新和插入操作

-- A用户对id=1的记录进行加锁
select * from user where id=1 for update;-- B用户无法对该记录进行操作
update user set count=10 where id=1;-- A用户commit以后则B用户可以对该记录进行操作

行锁的实现需要注意:

  1. 行锁必须有索引才能实现,否则会自动锁全表,那么就不是行锁了。

  2. 两个事务不能锁同一个索引。

  3. insert,delete,update在事务中都会自动默认加上排它锁。

行锁场景:

A用户消费,service层先查询该用户的账户余额,若余额足够,则进行后续的扣款操作;这种情况查询的时候应该对该记录进行加锁。

否则,B用户在A用户查询后消费前先一步将A用户账号上的钱转走,而此时A用户已经进行了用户余额是否足够的判断,则可能会出现余额已经不足但却扣款成功的情况。

为了避免此情况,需要在A用户操作该记录的时候进行for update加锁

扩展:间隙锁

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

InnoDB也会对这个"间隙"加锁,这种锁机制就是所谓的间隙锁

-- 用户A
update user set count=8 where id>2 and id<6-- 用户B
update user set count=10 where id=5;

如果用户A在进行了上述操作后,事务还未提交,则B无法对2~6之间的记录进行更新或插入记录,会阻塞,当A将事务提交后,B的更新操作会执行。

建议:

  • 尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁

  • 合理设计索引,尽量缩小锁的范围

  • 尽可能减少索引条件,避免间隙锁

  • 尽量控制事务大小,减少锁定资源量和时间长度

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/576186.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Thinking In Design Pattern——Query Object模式

什么是Query Object模式 Query Object的架构设计 Query Object在服务层的应用 测试 Query Object模式 Query Object&#xff1a;可以在领域服务层构造查询然后传给资源库使用&#xff0c;并使用某种查询翻译器将对象查询&#xff08;Query&#xff09;翻译成底层数据库持久化…

linux gcc编译C程序 分享

一个c语言程序从源文件到生成可执行文件&#xff0c;编译器需要共经历4个步骤&#xff1a;1) 预处理&#xff1a;把c文件中预处理命令扫描处理完毕&#xff0c;即对源代码文件中的文件包含(#include)、预编译语句(如宏定义#define等)进行分析&#xff0c;此时生成的文件仍然是可…

java Arrays.copyOfRange使用方法

使用场景&#xff1a;比如当一个文本框输入多个值作为查询条件&#xff0c;这时候当输入的值过多&#xff0c;我们需要最大支持多少个&#xff1f;这时候&#xff0c;输入超出个数的值&#xff0c;就被截取不要 不然后台处理逻辑就要飞前台返回不能查询这样的提示&#xff0c;…

WinForm 中 comboBox控件之数据绑定

http://www.cnblogs.com/peterzb/archive/2009/05/30/1491923.html 下面介绍三种对comboBox绑定的方式&#xff0c;分别是泛型中IList和Dictionary&#xff0c;还有数据集DataTable 一、IList 现在我们直接创建一个List集合&#xff0c;然后绑定 View Code IList<string>…

MySQL常用引擎有MyISAM和InnoDB区别

MySQL常用引擎有MyISAM和InnoDB&#xff0c;而InnoDB是mysql默认的引擎。MyISAM不支持行锁&#xff0c;而InnoDB支持行锁和表锁。 如何加锁&#xff1f; MyISAM在执行查询语句&#xff08;SELECT&#xff09;前&#xff0c;会自动给涉及的所有表加读锁&#xff0c;在执行更新…

java中异常与return

抽时间整理了下java中异常与return&#xff0c;以前这块总是弄混淆&#xff0c;觉得还是写下来慢慢整理比较好。由于水平有限&#xff0c;仅供参考。废话不多说&#xff0c;直接上代码。 下面是两个方法&#xff1a; 1 public static int throwReturn(){2 int ret…

rocketmq 启动mqbroker.cmd闪退

非常奇怪&#xff0c;broker启动闪退&#xff0c;我就摸索了好久&#xff0c;网上各种百度&#xff0c;最后得到正解 将c盘下这个store下的文件全部删除&#xff0c;就可以启动了 猜测是可能mq非正常关闭&#xff0c;导致&#xff0c;具体懂原理的大佬可以来评论区说说

星星计算器

星星计算器&#xff1a; [ 机锋下载 ]第一款&#xff0c;呃&#xff0c;…&#xff0c;自家学习安卓的时候产的&#xff0c;功能和第二款有些类似&#xff08;而且在细节功能方面我也做了很多努力&#xff09;&#xff0c;不过已经十分强大了&#xff0c;并且有自己的创新&…

java基础复习-(run方法和start方法区别)

1&#xff0c;run方法是Runnable接口中定义的&#xff0c;start方法是Thread类定义的。 所有实现Runnable的接口的类都需要重写run方法&#xff0c;run方法是线程默认要执行的方法&#xff0c;是绑定操作系统的&#xff0c;也是线程执行的入口。 start方法是Thread类的默认执行…

Web.py Cookbook 简体中文版 - 如何使用web.background

注意&#xff01;&#xff01; web.backgrounder已转移到web.py 3.X实验版本中&#xff0c;不再是发行版中的一部分。你可以在这里下载&#xff0c;要把它与application.py放置在同一目录下才能正运行。 介绍 web.background和web.backgrounder都是python装饰器&#xff0c;它可…

为什么wait, notify,notifyAll保存在Object类中,而不是Thread类

一个较难回答的 Java 问题&#xff0c; Java 编程语言又不是你设计的&#xff0c;你如何回答这个问题呢&#xff1f; 需要对 Java 编程的常识进行深入了解才行。 这个问题的好在它能反映面试者是否对 wait - notify 机制有没有了解, 以及他相关知识的理解是否明确。就像为什么…

Springboot集成MapperFactory(ma.glasnost.orika.MapperFactory)类属性复制

导入jar <dependency><groupId>ma.glasnost.orika</groupId><artifactId>orika-core</artifactId><version>1.5.2</version></dependency> 编写容器注入的类 package com.kingboy.springboot.config;import ma.glasnost.or…

WPF之布局

此文目的旨在让人快速了解&#xff0c;没有什么深度&#xff0c;如需深入了解布局&#xff0c;请参考msdn。 如果你要把WPF当winform使用&#xff0c;拖拖控件也无不可&#xff0c;不过建议还是不要拖的好。 本文将那些用的比较多的几个布局控件&#xff08;Grid、UniformGrid、…

@Size、@Max、@Min、@Length、注解的含义和区别

Min 验证 Number 和 String 对象是否大等于指定的值Max 验证 Number 和 String 对象是否小等于指定的值Size(min, max) 验证对象&#xff08;Array,Collection,Map,String&#xff09;长度是否在给定的范围之内Length(min, max) 验证字符串长度是否在给定的范围之内区别&#x…

C# WCF WinCE 解决方案 错误提示之:已超过传入消息(65536)的最大消息大小配额。若要增加配额,请使用相应绑定元素上的 MaxReceivedMessageSize 属性...

C# WCF WinCE 解决方案 错误提示之&#xff1a;已超过传入消息(65536)的最大消息大小配额。若要增加配额&#xff0c;请使用相应绑定元素上的 MaxReceivedMessageSize 属性 网上的解决方案&#xff1a; 出现这种错误&#xff0c;先去修改服务器端和客户端的MaxReceivedMessageS…

mybatis xml返回对象类型和接口定义类型不一致

最近在开发中发现xml定义的返回值类型xxxxMaper.xml <select id"selectPlanList" parameterType"Plan" resultMap"PlanListVo">select * from table_name</select> <resultMap type"com.demo.vo.PlanListVo" id"…

算法可视化

http://www.cs.usfca.edu/~galles/visualization/ComparisonSort.html http://jsrun.it/norahiko/oxIy转载于:https://www.cnblogs.com/hailuo/archive/2012/12/06/2805400.html

Springboot @Validated和@Valid的区别 及使用

Valid是使用Hibernate validation的时候使用 Validated是只用Spring Validator校验机制使用 说明&#xff1a;java的JSR303声明了Valid这类接口&#xff0c;而Hibernate-validator对其进行了实现 Validation对Valid进行了二次封装&#xff0c;在使用上并没有区别&#xff0c…

【dp】CF17C. Balance

http://codeforces.com/problemset/problem/17/C 题目中给出一个仅含有a,b,c的字符串&#xff0c;已经两种操作每次选出任意两个相邻的字符&#xff0c;用第一个覆盖掉第二个或者反之&#xff0c;最后询问不考虑操作次数&#xff0c;最终有多少种不同的序列其中a&#xff0c;b,…

git常用的命令收集

1.强制推送&#xff08;慎用&#xff0c;除非你认为其他冲突等可以丢弃 或者不是很重要&#xff09;git push -- force git—全局设置用户名、密码、邮箱 git config命令的–global参数&#xff0c;用了这个参数&#xff0c;表示你这台机器上所有的Git仓库都会使用这个配置&…