【MySQL】16.事务管理(重点) -- 2

1. 事务隔离级别

如何理解隔离性1

  • MySQL服务可能会同时被多个客户端进程(线程)访问,访问的方式以事务方式进行
  • 一个事务可能由多条SQL构成,也就意味着,任何一个事务,都有执行前,执行中,执行后的阶段。而所谓的原子性,其实就是让用户层,要么看到执行前,要么看到执行后。执行中出现问题,可以随时回滚。所以单个事务,对用户表现出来的特性,就是原子性。
  • 但,毕竟所有事务都要有个执行过程,那么在多个事务各自执行多个SQL的时候,就还是有可能会出现互相影响的情况。比如:多个事务同时访问同一张表,甚至同一行数据。
  • 就如同你妈妈给你说:你要么别学,要学就学到最好。至于你怎么学,中间有什么困难,你妈妈不关心。那么你的学习,对你妈妈来讲,就是原子的。那么你学习过程中,很容易受别人干扰,此时,就需要将你的学习隔离开,保证你的学习环境是健康的。
  • 数据库中,为了保证事务执行过程中尽量不受干扰,就有了一个重要特征:隔离性
  • 数据库中,允许事务受不同程度的干扰,就有了一种重要特征:隔离级别

2. 隔离级别

  • 读未提交【Read Uncommitted】: 在该隔离级别,所有的事务都可以看到其他事务没有提交的执行结果。(实际生产中不可能使用这种隔离级别的),但是相当于没有任何隔离性,也会有很多并发问题,如脏读,幻读,不可重复读等,我们上面为了做实验方便,用的就是这个隔离性。
  • 读提交【Read Committed】 :该隔离级别是大多数数据库的默认的隔离级别(不是 MySQL 默认的)。它满足了隔离的简单定义:一个事务只能看到其他的已经提交的事务所做的改变。这种隔离 级别会引起不可重复读,即一个事务执行时,如果多次select, 可能得到不同的结果。
  • 可重复读【Repeatable Read】: 这是 MySQL 默认的隔离级别,它确保同一个事务,在执行中,多次读取操作数据时,会看到同样的数据行。但是会有幻读问题。
  • 串行化【Serializable】: 这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决了幻读的问题。它在每个读的数据行上面加上共享锁,。但是可能会导致超时和锁竞争 (这种隔离级别太极端,实际生产基本不使用)

隔离级别如何实现:隔离,基本都是通过锁实现的,不同的隔离级别,锁的使用是不同的。
常见有,表锁,行锁,读锁,写锁,间隙锁(GAP),Next-Key锁(GAP+行锁)等。
不过,我们目前现有这个认识就行,先关注上层使用。

3. 查看与设置隔离性

-- 查看
mysql> SELECT @@global.tx_isolation; --查看全局隔级别
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
|       REPEATABLE-READ |
+-----------------------+
1 row in set, 1 warning (0.00 sec)mysql> SELECT @@session.tx_isolation; --查看会话(当前)全局隔级别
+------------------------+
| @@session.tx_isolation |
+------------------------+
|        REPEATABLE-READ |
+------------------------+
1 row in set, 1 warning (0.00 sec)mysql> SELECT @@tx_isolation; --默认同上
+-----------------+
|  @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)
-- 设置
-- 设置当前会话 or 全局隔离级别语法
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL
{READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
-- 设置当前会话隔离性,另起一个会话,看不多,只影响当前会话
mysql> set session transaction isolation level serializable; -- 串行化
Query OK, 0 rows affected (0.00 sec)mysql> SELECT @@global.tx_isolation; --全局隔离性还是RR
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
|       REPEATABLE-READ |
+-----------------------+
1 row in set, 1 warning (0.00 sec)mysql> SELECT @@session.tx_isolation; --会话隔离性成为串行化
+------------------------+
| @@session.tx_isolation |
+------------------------+
|           SERIALIZABLE |
+------------------------+
1 row in set, 1 warning (0.00 sec)mysql> SELECT @@tx_isolation; --同上
+----------------+
| @@tx_isolation |
+----------------+
|   SERIALIZABLE |
+----------------+
1 row in set, 1 warning (0.00 sec)--设置全局隔离性,另起一个会话,会被影响
mysql> set global transaction isolation level READ UNCOMMITTED;
Query OK, 0 rows affected (0.00 sec)mysql> SELECT @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
|      READ-UNCOMMITTED |
+-----------------------+
1 row in set, 1 warning (0.00 sec)mysql> SELECT @@session.tx_isolation;
+------------------------+
| @@session.tx_isolation |
+------------------------+
|       READ-UNCOMMITTED |
+------------------------+
1 row in set, 1 warning (0.00 sec)mysql> SELECT @@tx_isolation;
+------------------+
|   @@tx_isolation |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set, 1 warning (0.00 sec)-- 注意,如果没有现象,关闭mysql客户端,重新连接。

3.1 读未提交【Read Uncommitted】

--几乎没有加锁,虽然效率高,但是问题太多,严重不建议采用
--终端A
-- 设置隔离级别为 读未提交
mysql> set global transaction isolation level read uncommitted;
Query OK, 0 rows affected (0.00 sec)--重启客户端
mysql> select @@tx_isolation;
+------------------+
|   @@tx_isolation |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set, 1 warning (0.00 sec)mysql> select * from account;
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |   100.00 |
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)mysql> begin; --开启事务
Query OK, 0 rows affected (0.00 sec)mysql> update account set blance=123.0 where id=1; --更新指定行
Query OK, 1 row affected (0.05 sec)
Rows matched: 1 Changed: 1 Warnings: 0
--没有commit哦!!!
--终端B
mysql> begin;
Query OK, 0 rows affected (0.00 sec)mysql> select * from account;
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |   123.00 | --读到终端A更新但是未commit的数据[insert,delete同样]
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)
-- 一个事务在执行中,读到另一个执行中事务的更新(或其他操作)但是未commit的数据,这种现象叫做脏读(dirty read)

3.2 读提交【Read Committed】 — 又名不可重复读

-- 终端A
mysql> set global transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)--重启客户端
mysql> select * from account; --查看当前数据
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |   123.00 | 
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)mysql> begin; --手动开启事务,同步的开始终端B事务
Query OK, 0 rows affected (0.00 sec)mysql> update account set blance=321.0 where id=1; --更新张三数据
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0--切换终端到终端B,查看数据。mysql> commit; --commit提交!
Query OK, 0 rows affected (0.01 sec)--切换终端到终端B,再次查看数据。
--终端B
mysql> begin; --手动开启事务,和终端A一前一后
Query OK, 0 rows affected (0.00 sec)mysql> select * from account; --终端A commit之前,查看不到
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |   123.00 | --老的值
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)--终端A commit之后,看到了!
--but,此时还在当前事务中,并未commit,那么就造成了,同一个事务内,同样的读取,在不同的时间段
(依旧还在事务操作中!),读取到了不同的值,这种现象叫做不可重复读(non reapeatable read)!!
(这个是问题吗??)
mysql> select *from account;
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |   321.00 | --新的值
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)

3.3 可重复读【Repeatable Read】

--终端A
mysql> set global transaction isolation level repeatable read; --设置全局隔离级别RR
Query OK, 0 rows affected (0.01 sec)--关闭终端重启mysql> select @@tx_isolation;
+-----------------+
|  @@tx_isolation |
+-----------------+
| REPEATABLE-READ | --隔离级别RR
+-----------------+
1 row in set, 1 warning (0.00 sec)mysql> select *from account; --查看当前数据
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |   321.00 | 
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)mysql> begin; --开启事务,同步的,终端B也开始事务
Query OK, 0 rows affected (0.00 sec)mysql> update account set blance=4321.0 where id=1; --更新数据
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0--切换到终端B,查看另一个事务是否能看到
--终端B
mysql> begin;
Query OK, 0 rows affected (0.00 sec)mysql> select * from account; --终端A中事务 commit之前,查看当前表中数据,数据未更新
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |   321.00 | 
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)mysql> select * from account; --终端A中事务 commit 之后,查看当前表中数据,数据未更新
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |  321.00 | 
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)--可以看到,在终端B中,事务无论什么时候进行查找,看到的结果都是一致的,这叫做可重复读!mysql> commit; --结束事务
Query OK, 0 rows affected (0.00 sec)mysql> select * from account; --再次查看,看到最新的更新数据
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |  4321.00 | 
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)

实验2:

--如果将上面的终端A中的update操作,改成insert操作,会有什么问题??
--终端Amysql> select *from account;
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |   321.00 | 
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)mysql> begin; --开启事务,终端B同步开启
Query OK, 0 rows affected (0.00 sec)mysql> insert into account (id,name,blance) values(3, '王五', 5432.0);
Query OK, 1 row affected (0.00 sec)--切换到终端B,查看另一个事务是否能看到mysql> commit; --提交事务
Query OK, 0 rows affected (0.00 sec)--切换终端到终端B,查看数据。
mysql> select * from account;
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |  4321.00 | 
|  2 |    李四 | 10000.00 |
|  3 |    王五 |  5432.00 |
+----+--------+----------+
3 rows in set (0.00 sec)
--终端B
mysql> begin; --开启事务
Query OK, 0 rows affected (0.00 sec)mysql> select * from account; --终端A commit前 查看
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |   321.00 | 
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)
mysql> select * from account; --终端A commit后 查看
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |   321.00 | 
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)

在这里插入图片描述

mysql> commit; --结束事务
Query OK, 0 rows affected (0.00 sec)mysql> select * from account; --看到更新
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |  4321.00 | 
|  2 |    李四 | 10000.00 |
|  3 |    王五 |  5432.00 |
+----+--------+----------+
3 rows in set (0.00 sec)

3.4 串行化【serializable】

-- 对所有操作全部加锁,进行串行化,不会有问题,但是只要串行化,效率很低,几乎完全不会被采用
-- 终端A
mysql> set global transaction isolation level serializable;
Query OK, 0 rows affected (0.00 sec)mysql> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
|   SERIALIZABLE |
+----------------+
1 row in set, 1 warning (0.00 sec)mysql> begin; --开启事务,终端B同步开启
Query OK, 0 rows affected (0.00 sec)mysql> select * from account; --两个读取不会串行化,共享锁
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |  4321.00 | 
|  2 |    李四 | 10000.00 |
|  3 |    王五 |  5432.00 |
+----+--------+----------+
3 rows in set (0.00 sec)mysql> update account set blance=1.00 where id=1; --终端A中有更新或者其他操作,会阻塞。直到终端B事务提交。
Query OK, 1 row affected (18.19 sec)
Rows matched: 1 Changed: 1 Warnings: 0
--终端B
mysql> begin;
Query OK, 0 rows affected (0.00 sec)mysql> select * from account; --两个读取不会串行化
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |  4321.00 | 
|  2 |    李四 | 10000.00 |
|  3 |    王五 |  5432.00 |
+----+--------+----------+
3 rows in set (0.00 sec)mysql> commit; --提交之后,终端A中的update才会提交。
Query OK, 0 rows affected (0.00 sec)

在这里插入图片描述

3.5 总结:

  • 其中隔离级别越严格,安全性越高,但数据库的并发性能也就越低,往往需要在两者之间找一个平衡点。
  • 不可重复读的重点是修改和删除:同样的条件, 你读取过的数据,再次读取出来发现值不一样了
  • 幻读的重点在于新增:同样的条件, 第1次和第2次读出来的记录数不一样
  • 说明: mysql 默认的隔离级别是可重复读,一般情况下不要修改
  • 上面的例子可以看出,事务也有长短事务这样的概念。事务间互相影响,指的是事务在并行执行的时候,即都没有commit的时候,影响会比较大。

在这里插入图片描述
一致性(Consistency)

  • 事务执行的结果,必须使数据库从一个一致性状态,变到另一个一致性状态。当数据库只包含事务成功提交的结果时,数据库处于一致性状态。如果系统运行发生中断,某个事务尚未完成而被迫中断,而改未完成的事务对数据库所做的修改已被写入数据库,此时数据库就处于一种不正确(不一致)的状态。因此一致性是通过原子性来保证的。
  • 其实一致性和用户的业务逻辑强相关,一般MySQL提供技术支持,但是一致性还是要用户业务逻辑做支撑,也就是,一致性,是由用户决定的。
  • 而技术上,通过AID保证C

推荐阅读

https://www.jianshu.com/p/398d788e1083
https://tech.meituan.com/2014/08/20/innodb-lock.html
https://www.cnblogs.com/aspirant/p/9177978.html

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Linux 动静态库的制作,使用和加载

Linux 动静态库的制作,使用和加载 一.前置说明1.mylib.h2.mylib.c3.mymath.h mymath.c4.如何制作库 二.动静态库的制作1.静态库的制作1.制作2.使用一下静态库,验证是否成功打包 2.动态库的制作1.编译.c源文件文件生成.o目标文件2.打包生成动态库3.编写makefile文件,自动化制作动…

【SpringCloud】Ribbon负载均衡

🏡浩泽学编程:个人主页 🔥 推荐专栏:《深入浅出SpringBoot》《java对AI的调用开发》 《RabbitMQ》《Spring》《SpringMVC》《项目实战》 🛸学无止境,不骄不躁,知行合一 文章目录 …

警惕.360勒索病毒:如何预防.360勒索病毒攻击

导言: 在网络安全领域,勒索病毒是一种非常危险的恶意软件,它以其独特的加密方式和高昂的赎金要求,给个人和企业带来了严重的损失。.360勒索病毒便是其中之一,它属于BeijingCrypt勒索病毒家族,具有高度的隐…

NO12 蓝桥杯单片机之DS1302的使用

1 DS1302是什么 DS1302由两块存储器组成,一个是日历时钟寄存器还有一个是31位的静态RAM存储器。 而在蓝桥杯中常考的就是日历时钟寄存器,故这里只介绍日历时钟寄存器。简单来说,其就是一个“电子表”,他会自动的实时记录时间&am…

Suno - AI自动作曲

文章目录 关于 Suno创作歌词结构曲风 关于 Suno Suno 是一款自动编曲工具。 官网 :https://www.suno.ai Suno is building a future where anyone can make great music. Whether you’re a shower singer or a charting artist, we break barriers between you …

关于Devc++调试的问题以及解决STL变量无法查看

目前Devc的调试主要有以下几点: 1.调试不能直接查看stl变量,会卡死不动 2.目前单步进入只能用鼠标键按 3.若想按下一步进入函数体内,要在函数体内打上断点才行 4.调试到return 0 ;上一句就停了,不会结束程序 5.目前F2跳至断点…

matplotlib 绘图

matplotlib 绘图 方便设置legend图例的位置 ax1.legend(loc‘upper center’, bbox_to_anchor(0.3, -0.1)) ax2.legend(loc‘upper center’, bbox_to_anchor(0.6, -0.1)) import numpy as np import matplotlib.pyplot as plt from scipy.stats import norm from scipy.inter…

SpringBoot Redis的使用

官方文档: 官方文档:Spring Data Redis :: Spring Data Redis 和jedis一样,SpringBoot Redis 也可以让我在Java代码中使用redis,同样也是通过引入maven依赖的形式。 加速访问github: 使用steam可以免费加速访问github Spring…

HarmonyOS实战开发-目标管理、如何实现一个自定义弹窗。

介绍 本篇Codelab将介绍如何使用State、Prop、Link、Watch、Provide、Consume管理页面级变量的状态,实现对页面数据的增加、删除、修改。要求完成以下功能: 实现一个自定义弹窗,完成添加子目标的功能。实现一个可编辑列表,可点击…

Android14之深入理解sp模板类(二百零二)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…

Android R 广播注册与发送流程分析

静态广播注册时序图 动态广播注册时序图 发送广播时序图 前言 广播接收器可以分为动态和静态,静态广播接收器就是在 AndroidManifest.xml 中注册的,而动态的广播接收器是在代码中通过 Context#registerReceiver() 注册的。 这里先从静态广播的流程开始…

2020年天津市二级分类土地利用数据(矢量)

天津市,位于华北平原海河五大支流汇流处,东临渤海,北依燕山。地势以平原和洼地为主,北部有低山丘陵,海拔由北向南逐渐下降,地貌总轮廓为西北高而东南低。天津有山地、丘陵和平原三种地形,平原约…

深夜变电站三维可视化:电力之心的全新解读

在寂静的深夜,城市的灯火依旧璀璨夺目,而在这背后,有一个不为人知的守护者正在默默工作——那就是变电站。如今,随着科技的飞速发展,我们有了更直观、更生动的方式来了解这个神秘的电力枢纽——三维可视化技术。 深夜变…

前端超分辨率技术应用:图像质量提升与场景实践探索-设计篇

超分辨率! 引言 在数字化时代,图像质量对于用户体验的重要性不言而喻。随着显示技术的飞速发展,尤其是移动终端视网膜屏幕的广泛应用,用户对高分辨率、高质量图像的需求日益增长。然而,受限于网络流量、存储空间和图像…

如何在Win10使用IIS服务搭建WebDAV网站并实现无公网IP访问内网文件内容

文章目录 前言1. 安装IIS必要WebDav组件2. 客户端测试3. 使用cpolar内网穿透,将WebDav服务暴露在公网3.1 安装cpolar内网穿透3.2 配置WebDav公网访问地址 4. 映射本地盘符访问 前言 在Windows上如何搭建WebDav,并且结合cpolar的内网穿透工具实现在公网访…

com.alibaba.boot.nacos.config.binder.NacosBootConfigurationPropertiesBinder解决记录

一直正常的服务突然启动失败了,控制台报错 查询后发现是spring-boot-starter版本2.4和nacos-config 0.2.8版本冲突了 于是看了下nacos-config版本,发现有两个如下 但是原来启动正常,看了下老版本代码发现nacos-config-springboot-autoconfig…

接口自动化测试——文件上传/下载

简介: 轻松搞定文件上传接口和文件下载接口。 我们在做接口自动化测试的时候,经常会碰到文件上传接口和文件下载接口。 那么,文件接口跟普通接口有什么区别呢?又该如何实现呢? 〇、前言 文件上传/下载接口与普通接…

怎么让ChatGPT批量写作原创文章

随着人工智能技术的不断发展,自然语言处理模型在文本生成领域的应用也日益广泛。ChatGPT作为其中的佼佼者之一,凭借其强大的文本生成能力和智能对话特性,为用户提供了一种高效、便捷的批量产出内容的解决方案。以下将就ChatGPT批量写作内容进…

colmap 【Feature matching】特征匹配参数解释

(Windows)Colmap 具体使用教程可参考我的这篇博文 下面只是matching参数解释 Matching这个阶段很重要,匹配方式不同会对最终结果影响很大,要根据实际情况选择合适的匹配方式。下面是各个参数的详细解释。 1.Exhaustive——官方文…

OSPF---开放式最短路径优先协议

1. OSPF描述 OSPF协议是一种链路状态协议。每个路由器负责发现、维护与邻居的关系,并将已知的邻居列表和链路费用LSU报文描述,通过可靠的泛洪与自治系统AS内的其他路由器周期性交互,学习到整个自治系统的网络拓扑结构;并通过自治系统边界的路…