Mysql事务隔离级别与锁机制

2023-10-26

事务及其ACID属性

  • 原子性(Atomicity):在同一个事务中的语句,要么同时生效要么同时失败
  • 一致性:在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性。
  • 隔离性(Isolation):事务与事务之间不能互相影响
  • 持久性(Durable) :事务一旦提交,就要永久保存。

并发事务处理带来的问题

问题 描述
脏读 读到其他事务未提交的事务
脏写 两个事务同时写一行数据,后面的覆盖了前面的那条。
不可重复读 在事务中重复执行相同查询语句,得到的结果不一样
幻读 在事务中重复执行相同查询语句,会得到其他事务提交的记录

隔离级别

mysql默认是可重读读。如果spring不指定就是这个级别,spring事务有指定的话优先spring

隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
读已提交
可重复度(REPEATABLE-READ)
串行化

设置隔离级别

5.7查看隔离级别
show variables like 'tx_isolation';
8.0查看隔离级别
SHOW VARIABLES LIKE 'transaction_isolation';
5.7设置隔离级别
set tx_isolation='REPEATABLE-READ';
8.8设计隔离级别
set transaction_isolation='REPEATABLE-READ';

  • 从性能上分为乐观锁(用版本对比来实现)和悲观锁
  • 从对数据库操作的类型分,分为读锁和写锁(都属于悲观锁)
    读锁(共享锁,S锁(Shared)):针对同一份数据,多个读操作可以同时进行而不会互相影响
    写锁(排它锁,X锁(eXclusive)):当前写操作没有完成前,它会阻断其他写锁和读锁
  • 从对数据操作的粒度分,分为表锁和行锁

总结:
MyISAM在执行查询语句SELECT前,会自动给涉及的所有表加读锁,在执行update、insert、delete操作会自动给涉及的表加写锁。
InnoDB在执行查询语句SELECT时(非串行隔离级别),不会加锁。但是update、insert、delete操作会加行锁。
简而言之,就是读锁会阻塞写,但是不会阻塞读。而写锁则会把读和写都阻塞。

表锁测试

#手动增加表锁 read 加读 write加写 逗号后可批量
lock table 表名称 read(write),表名称2 read(write);
#查看表上加过的锁
show open tables;
#删除表锁
unlock tables;

session1对表A加了读锁,那么在session1和其他session中都可读。如果在session1中写数据报错,其他session写数据会阻塞

session1对表A加了写锁,session1中可读可写。其他session对该表的所有操作被阻塞

行锁测试(仅限innodb)

for update 行X锁
lock in share mode 行S锁

#事务一
start TRANSACTION;
select * from account where id = 1 for UPDATE;

#事务二 不管加S锁还是X锁都会阻塞
select * from account where id = 1 for UPDATE;
select * from account where id = 1 for lock in share mode;

case2

#事务一
start TRANSACTION;
select * from account where id = 1 for lock in share mode;

#事务二 加X锁阻塞 加S锁可以正常查出数据
select * from account where id = 1 for UPDATE;
select * from account where id = 1 for lock in share mode;

case3

#事务一
start TRANSACTION;
select * from account where id = 1 for UPDATE;
#事务二 在除了串行化的隔离级别情况下直接select是不会加S锁,所以这样可以读取成功
select * from account where id = 1 ;

start TRANSACTION; 后记得commit。在除了串行化的隔离级别情况下,一般的select是不会加S锁的,除非手动for lock in share mode,在串行化隔离级别情况下,普通的select也会加S锁。因为这样可以防止幻读的情况

幻读测试

在可重复度的隔离级别下
1.首先开启一个事务进行查询

start TRANSACTION;
select * from account

在这里插入图片描述

2.再创建一共事务插入一条新数据

insert into account (id,name,balance) VALUES (4,'cyz',600);

3.事务一 再次查询
在这里插入图片描述
4.事务一 查不到插入的最新数据,但是这时执行update语句后再查询,发现竟然可以读取到事务,这就是幻读。

UPDATE account SET name = 'mm' where id = 4

在这里插入图片描述

可重复读和java代码之间的问题

1.开启一个事务一,执行查询。
在这里插入图片描述
2.开启事务二,修改mm 减去 100,并提交
3.事务一再次查询,mm依然是600,但是实际库中已经变成500
4.事务一执行修改语句,并不提交事务

UPDATE account SET balance = balance-100 where id = 4

5.在事务一中再次查询,发现结果是400并没有错误,并没有因为select是600而修改错数据。
6.证明在不可重复读的情况下,相同的select语句虽然每次查的都是一样,但是真实数据并不是和查出来的一样。有一个类似副本的东西(并不是副本而是mvcc机制),但是修改又可以正确处理。保证了最终一致性,做一个类似副本的东西只是为了帮助程序员可以清晰的开发代码,不然每次查的都不一样,无法很好的做判断。

注意:

# 可以正确跟新
UPDATE account SET balance = balance-100 where id = 4

java中

 // 获得库存
Account account = accountMapper.getById(4);
 // 各种业务操作
 //设置库存
account.setBalance(400);
accountMapper.updateById(account);

在这种java代码中 先获取库存再set,如果这时库存改变了,并不能像sql语句一样保持最终一致性。
得使用java锁的机制来规避

# 错误 java代码最后执行的是这句
UPDATE account SET balance = 400 where id = 4
# 正确
UPDATE account SET balance = balance-100 where id = 4

间隙锁(Gap Lock) 和 临键锁(Next-key Locks)

间隙锁是在可重复读隔离级别下才会生效。
间隙锁可以在某些情况下解决幻读。

假如表
在这里插入图片描述
在事务一中执行

update account set name = 'zhuge' where id > 5 and id <18;

则其他事务没法在这个范围所包含的所有行记录(包括间隙行记录)以及行记录所在的间隙里插入或修改任何数据,即id在(4,19]区间都无法修改数据,注意最后那个19也是包含在内的这个就是间隙锁

如果是

update account set name = 'zhuge' where id > 5 and id <31;

31大于了表里最大的记录。这时候锁的区间就是 (4,正无穷 )

临键锁(Next-key Locks) 就是行锁与间隙锁的组合。像上面那个例子里的这个(3,20]的整个区间可以叫做临键锁
区别:间隙锁只是锁住间隙,并没有锁住中间具体的行。临建锁加上那些真实存在的行锁。

意向锁(表级别的锁)

意向锁有两种

  • 意向共享锁(IS)表示事务意图在表中的单个行上设置共享锁。
  • 意向排他锁(IX)表明事务意图在表中的单个行上设置独占锁。

在给表或者行加上S锁时 会给加上IS锁
在给表或者行加上X锁时 会给加上IX锁

作用:如果事务一给某一行加上了X锁。事务二要加表锁。如果没有意向锁的话就要一行行的判断有没有行锁,非常麻烦。如果在加上X锁时,再给表加上一个意向锁。其他事务只要看一下有没有意向锁就知道能不能加表锁了。IS锁类似。
意向锁解释

无索引行锁会升级为表锁

行锁都是加载索引上,如果没有索引就会升级成表锁

行锁分析

show status like 'innodb_row_lock%';

在这里插入图片描述
这里的锁定是指第二个事务想获得锁的时候阻塞的情况,如果只有一个事务没有人和他竞争锁不会统计
Innodb_row_lock_current_waits: 当前正在等待锁定的数量
Innodb_row_lock_time: 从系统启动到现在锁定总时间长度
Innodb_row_lock_time_avg: 每次等待所花平均时间
Innodb_row_lock_time_max:从系统启动到现在等待最长的一次所花时间
Innodb_row_lock_waits:系统启动后到现在总共等待的次数

对于这5个状态变量,比较重要的主要是:
Innodb_row_lock_time_avg (等待平均时长)
Innodb_row_lock_waits (等待总次数)
Innodb_row_lock_time(等待总时长)
尤其是当等待次数很高,而且每次等待时长也不小的时候,我们就需要分析系统中为什么会有如此多的等待,
然后根据分析结果着手制定优化计划。

查看INFORMATION_SCHEMA系统库锁相关数据表

 # 查看事务
select * from INFORMATION_SCHEMA.INNODB_TRX;
# 查看锁5.7
select * from INFORMATION_SCHEMA.INNODB_LOCKS;
# 查看锁8.0
select * from performance_schema.data_locks
# 查看锁等待5.7
select * from INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
# 查看锁等待8.0
select * from performance_schema.data_lock_waits;



‐‐ 释放锁,trx_mysql_thread_id可以从INNODB_TRX表里查看到
kill trx_mysql_thread_id

 ‐‐ 查看锁等待详细信息
 show engine innodb status\G
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Mysql事务隔离级别与锁机制 的相关文章

  • JAXb、Hibernate 和 beans

    目前我正在开发一个使用 Spring Web 服务 hibernate 和 JAXb 的项目 1 我已经使用IDE hibernate代码生成 生成了hibernate bean 2 另外 我已经使用maven编译器生成了jaxb bean
  • 无法展开 RemoteViews - 错误通知

    最近 我收到越来越多的用户收到 RemoteServiceException 错误的报告 我每次给出的堆栈跟踪如下 android app RemoteServiceException Bad notification posted fro
  • Android MediaExtractor seek() 对 MP3 音频文件的准确性

    我在使用 Android 时无法在eek 上获得合理的准确度MediaExtractor 对于某些文件 例如this one http www archive org download emma solo librivox emma 01
  • 多个 Maven 配置文件激活多个 Spring 配置文件

    我想在 Maven 中构建一个环境 在其中我想根据哪些 Maven 配置文件处于活动状态来累积激活多个 spring 配置文件 目前我的 pom xml 的相关部分如下所示
  • JavaMail 只获取新邮件

    我想知道是否有一种方法可以在javamail中只获取新消息 例如 在初始加载时 获取收件箱中的所有消息并存储它们 然后 每当应用程序再次加载时 仅获取新消息 而不是再次重新加载它们 javamail 可以做到这一点吗 它是如何工作的 一些背
  • Liferay ClassNotFoundException:DLFileEntryImpl

    在我的 6 1 0 Portal 实例上 带有使用 ServiceBuilder 和 DL Api 的 6 1 0 SDK Portlet 这一行 DynamicQuery query DynamicQueryFactoryUtil for
  • 操作错误不会显示在 JSP 上

    我尝试在 Action 类中添加操作错误并将其打印在 JSP 页面上 当发生异常时 它将进入 catch 块并在控制台中打印 插入异常时出错 请联系管理员 在 catch 块中 我添加了它addActionError 我尝试在jsp页面中打
  • 无法解析插件 Java Spring

    我正在使用 IntelliJ IDEA 并且我尝试通过 maven 安装依赖项 但它给了我这些错误 Cannot resolve plugin org apache maven plugins maven clean plugin 3 0
  • 一次从多个表中删除行

    我正在尝试将 2 个查询合并为一个这样的查询 result db gt query DELETE FROM menu WHERE name new or die db gt error result db gt query DELETE F
  • 如何为俚语和表情符号构建正则表达式 (regex)

    我需要构建一个正则表达式来匹配俚语 即 lol lmao imo 等 和表情符号 即 P 等 我按照以下示例进行操作http www coderanch com t 497238 java java Regular Expression D
  • 如何将 pfx 文件转换为 jks,然后通过使用 wsdl 生成的类来使用它来签署传出的肥皂请求

    我正在寻找一个代码示例 该示例演示如何使用 PFX 证书通过 SSL 访问安全 Web 服务 我有证书及其密码 我首先使用下面提到的命令创建一个 KeyStore 实例 keytool importkeystore destkeystore
  • JRE 系统库 [WebSphere v6.1 JRE](未绑定)

    将项目导入 Eclipse 后 我的构建路径中出现以下错误 JRE System Library WebSphere v6 1 JRE unbound 谁知道怎么修它 右键单击项目 特性 gt Java 构建路径 gt 图书馆 gt JRE
  • 使用Caliper时如何指定命令行?

    我发现 Google 的微型基准测试项目 Caliper 非常有趣 但文档仍然 除了一些示例 完全不存在 我有两种不同的情况 需要影响 JVM Caliper 启动的命令行 我需要设置一些固定 最好在几个固定值之间交替 D 参数 我需要指定
  • 仅将 char[] 的一部分复制到 String 中

    我有一个数组 char ch 我的问题如下 如何将 ch 2 到 ch 7 的值合并到字符串中 我想在不循环 char 数组的情况下实现这一点 有什么建议么 感谢您花时间回答我的问题 Use new String value offset
  • Java执行器服务线程池[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 如果我使用 Executor 框架在
  • simpleframework,将空元素反序列化为空字符串而不是 null

    我使用简单框架 http simple sourceforge net http simple sourceforge net 在一个项目中满足我的序列化 反序列化需求 但在处理空 空字符串值时它不能按预期工作 好吧 至少不是我所期望的 如
  • 编译器抱怨“缺少返回语句”,即使不可能达到缺少返回语句的条件

    在下面的方法中 编译器抱怨缺少退货声明即使该方法只有一条路径 并且它包含一个return陈述 抑制错误需要另一个return陈述 public int foo if true return 5 鉴于Java编译器可以识别无限循环 https
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • 捕获的图像分辨率太大

    我在做什么 我允许用户捕获图像 将其存储到 SD 卡中并上传到服务器 但捕获图像的分辨率为宽度 4608 像素和高度 2592 像素 现在我想要什么 如何在不影响质量的情况下获得小分辨率图像 例如我可以获取或设置捕获的图像分辨率为原始图像分
  • java.lang.IllegalStateException:驱动程序可执行文件的路径必须由 webdriver.chrome.driver 系统属性设置 - Similiar 不回答

    尝试学习 Selenium 我打开了类似的问题 但似乎没有任何帮助 我的代码 package seleniumPractice import org openqa selenium WebDriver import org openqa s

随机推荐

  • 【Kafka】docker部署Kafka集群

    目录 Kafka概述 Kafka集群docker部署流程 简述 环境准备 部署流程 参考文献 Kafka概述 以下概述Kafka内的几个核心概念 可参考官方文档 有兴趣可读 kafka apache org Topic与日志 Topic 就
  • 第四篇、UDP消息发送

    文章目录 前言 一 UDP通信操作 二 代码示例 1 UDP消息发送 总结 前言 上一篇我们共同学习了TCP文件传输 本篇我们来学习UDP消息发送 一 UDP通信操作 发送方 1 建立一个socket连接 2 建立一个包 3 发送包 4 关
  • SSL VPN

    1 SSL工作过程是什么 第一阶段 客户端首先发送client hello消息到服务端 服务端收到client hello信息后 再发送server hello消息到客户端 随机数 32位时间戳 28字节随机序列 用于计算摘要信息和预主密钥
  • Java系列——封装、继承、多态初了解

    目录 一 前言 二 封装 1 什么是封装 2 封装的特点 3 封装的使用 三 继承 1 什么是继承 2 继承的特点 3 继承的优点 4 继承的使用 4 1 继承的格式 4 2 继承的演示 4 3 成员变量 4 4 成员方法 4 5 构造方法
  • Pyhton零售数据分析及产品关联分析

    一 项目背景 总结 项目背景 以购物篮分析为背景 分析某跨国棒球用品零售商的历史订单数据 为企业提供运营及销售策略 项目总结 一 本项目对企业历史订单数据进行以下角度的处理及分析 数据探索及清洗 对6w 订单数据进行探索及清洗处理 为数据构
  • 2022年最新前端面试题,持续更新

    js面试题 1 js数据类型 基本数据类型 Number String Boolean Null Undefined Symbol bigInt 引用数据类型 object Array Date Function RegExp 2 js变量
  • surf特征原理

    前言 也许我们使用过Uiautomator编写过自动化测试脚本 也许我们也使用过Monkey来测试过应用的稳定性 但在使用过程中总觉得有或多或小的问题 用Uiautomator写脚本 总觉得有时候控件没法识别 用Monkey来进行稳定性测试
  • Oracle SQL developer不显示dbms_output.put_line的输出内容

    1 调出dbms输出窗口 2 dbms选择对应的数据库连接 3 工作区SQL文件 定义一个触发器 create trigger newtmpdata 创建触发器newtmpdata 在tmp中添加新数据 after insert 插入操作之
  • yolo算法通俗易懂讲解

    参考 https blog csdn net briblue article details 103149407 depth 1 utm source distribute pc relevant none task utm source
  • .NET[C#]LINQ查询List集合中所有重复的元素如何实现?(转载)

    NET C LINQ查询List集合中所有重复的元素如何实现 转载 方案一 var query lst GroupBy x gt x Where g gt g Count gt 1 Select y gt y Key ToList 如果还需
  • C#,去除字符串指定的之字符,并去掉不可见的 “”一种方法。

    string str1 小王 心情 很 平 静 char chs1 new char 定义一个字符数组 存放上面字符串中不要的内容 和 string result1 str1 Split chs1 StringSplitOptions Re
  • 关于Adapter数据适配器

    适配器 什么是适配器 Android适配器是数据和视图之间的桥梁 以便于数据在View上显示 适配器就像显示器 把复杂的东西按人可以接受的方式来展现 Adapter数据适配器将各种数据以合适的形式绑定到控件上 像listview gridv
  • MyBatis框架——MyBatis执行SQL的两种方式(转载)

    本节主要介绍 MyBatis 执行 SQL 语句的两种方式和它们的区别 MyBatis 有两种执行 SQL 语句的方式 如下 通过 SqlSession 发送 SQL 通过 SqlSession 获取 Mapper 接口 通过 Mapper
  • ajax 无参请求,ajax无参请求学习

    ajax 点击 请求流程 test html代码流程 创建button按钮 为button绑定一个点击事件 函数 在函数内书写ajax代码 2 1 创建ajax对象 2 2 设置onreadystatechange属性 用来监听变化 如果有
  • 数据结构视频教程 -《数据结构视频教程 严蔚敏》

    整个视频打包下载地址 史上最全的数据结构视频教程系列分享之 数据结构视频教程 严蔚敏 转载请保留出处和链接 更多优秀资源请访问 我是码农 严蔚敏老师是清华大学计算机系教授 长期从事数据结构教学和教材建设 本教程是数据结构视频教程中的经典之作
  • Spring(十二):bean的加载——创建bean

    回顾 前面已经看了在加载Bean的时候 如何去解决循环依赖的问题 解决完循环依赖 就到创建Bean的步骤了 而创建bean的步骤是紧紧接着 创建Bean实例 Bean根据范围会分为几种 单例 原型 自定义范围 每种范围都会有自己不同的生命周
  • 【Altium designer】PCB 各层简介

    1 Signal Layer 信号层 主要用于放置元件和走线 Top Layer 顶层 Bottom Layer 底层 Mid Layer 中间信号层 2 Mechanical Layer 机械层 3 Keep Out Layer 禁止布线
  • Linux内核:内存管理——内存回收

    概述 当linux系统内存压力就大时 就会对系统的每个压力大的zone进程内存回收 内存回收主要是针对匿名页和文件页进行的 对于匿名页 内存回收过程中会筛选出一些不经常使用的匿名页 将它们写入到swap分区中 然后作为空闲页框释放到伙伴系统
  • c++学习之多态案例--电脑组装

    代码示例 include
  • Mysql事务隔离级别与锁机制

    文章目录 事务及其ACID属性 并发事务处理带来的问题 隔离级别 锁 表锁测试 行锁测试 仅限innodb 幻读测试 可重复读和java代码之间的问题 间隙锁 Gap Lock 和 临键锁 Next key Locks 意向锁 表级别的锁