当前位置: 首页 > news >正文

【MySQL】从零开始了解数据库开发 --- mysql事务机制(二)

在这里插入图片描述

真正的艺术家什么都不蔑视,
他们逼迫自己去理解,
而不是去评判。
-- 阿尔贝·加缪 --

从零开始了解数据库开发

  • 1 事务隔离基本
    • 1.1 如何理解事务隔离
    • 1.2 隔离级别
    • 1.3 查看隔离级别
  • 2 事务隔离级别
    • 2.1 读未提交 RU
    • 2.2 读提交 RC
    • 2.3 可重复读 RR
    • 2.4 串行化 serializabale
    • 2.5 总结
  • 3 事务隔离与数据一致性

1 事务隔离基本

1.1 如何理解事务隔离

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

1.2 隔离级别

在两个线程同时对数据库进行访问,假如现在应该线程Ainsert一条数据,然后另外一个线程B查询数据,那么这个线程查询到的结果里应不应该有线程A刚才插入的数据呢? 其实,有或者没有都是可能的,具体是由隔离级别决定的。如何理解隔离级别呢?我们列举几个场景:

  • 小明和爸爸妈妈,小明的父母在你出生前10年就相识了,但是对你来说,小明是无法准确知道历史上父母当时是怎么认识的,当然也可以由父母告诉小明。但是你的父母却可以知道所有你的事情。但当小明也60岁时,小明父母安然离世,那么小明父母也就无法知道小明之后的事情了。
  • 所以说:对于历史和未来的不一定是能读到的,但能保证自己生命周期内的事情是可以知道的。
  • 这就是所谓的隔离,事务中隔离是必要的,而究竟要隔离到什么程度,由隔离级别决定!

mysql中具体的4个隔离级别:

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

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

1.3 查看隔离级别

隔离级别有全局和会话两个,mysql打开一个客户端就是一个会话,默认会继承全局global的隔离级别,当然也可以更改当前会话的隔离级别,但不会影响全局的,也就是不影响新建立的会话的隔离级别

-- 查看
mysql> SELECT @@global.transaction_isolation; --查看全局隔级别
+-----------------------+
| @@global.transaction_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
1 row in set, 1 warning (0.00 sec)
mysql> SELECT @@session.transaction_isolation;--查看会话(当前)全局隔级别
+------------------------+
| @@session.transaction_isolation |
+------------------------+
| REPEATABLE-READ |
+------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> SELECT @@transaction_isolation; --默认同上
+-----------------+
| @@transaction_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 -- 串行化
}

我们可以来操作实验一下:
在这里插入图片描述
一般不推荐更改隔离级别,具体操作还是看情况。

2 事务隔离级别

了解了事务隔离级别的概念,接下来我们来看一下不同的事务隔离级别的现象有何不同。我们创建两个会话,来在不同的隔离级别下进行操作。

2.1 读未提交 RU

开启个事务,使用读未提交级别。
事务A这里进行insert但不进行提交, 事务B在事务Ainsert后读取一次
在这里插入图片描述
会发现事务B读到了事务A未提交的数据。这个隔离级别下,几乎没有加锁,不建议使用这个隔离级别!

一个事务在执行中,读到另一个执行中事务的更新(或其他操作)但是未commit的数据,这种现象叫做脏读(dirty read) 对于事务原子性的要求,显然脏读是不合理的!

2.2 读提交 RC

开启两个事务,使用读未提交级别。
事务A这里进行insert与update 提交, 事务B在事务Ainsert后读取一次 但是不commit结束
在这里插入图片描述
这样两个并发的事务,只有在事务A提交后,其他事务B才能读取到事务A修改的数据。

但是,此时还在当前事务中,并未commit,那么就造成了,同一个事务内,同样的读取,在不同的时间段(依旧还在事务操作中!),读取到了不同的值,这种现象叫做不可重复读(non reapeatable read)!!
**这个是问题吗???**是不是问题是真的具体业务来看的,我们用一个非常经典的例子:商品库存扣减

假设我们有一个商品表,商品ID为1,库存是100件。
初始数据:

-- product表
-- id | name | stock
-- 1  | '键盘' | 100

现在有两个并发操作:

  • 事务A:管理员后台查询商品1的库存,用于生成报表。
  • 事务B:用户下单,购买1件商品1,需要扣减库存。
场景一:不可重复读是“问题”

业务需求:管理员需要在一个事务内,先查询库存,再查询其他关联信息(比如预售订单),最后再次确认库存,确保数据在生成报表期间是稳定一致的。
执行流程(在 READ COMMITTED 隔离级别下):

  1. 事务A 开始,第一次查询库存:
    START TRANSACTION;
    SELECT stock FROM product WHERE id = 1;  -- 结果:100
    
    管理员看到库存是100。
  2. 事务B 开始,完成购买并提交:
    START TRANSACTION;
    UPDATE product SET stock = stock - 1 WHERE id = 1; -- 库存变为99
    COMMIT;
    
    用户成功下单,库存已更新。
  3. 事务A(还未结束)再次查询库存:
    SELECT stock FROM id = 1; -- 结果:99
    
    管理员在同一个事务内,两次查询同一个商品,却得到了不同的结果(100 -> 99)。

结论:在这个场景下,不可重复读是个问题。它破坏了事务内部的“一致性”和“隔离性”,导致报表数据逻辑上可能对不上(比如前面统计的库存总数和后面明细对不上)。这种业务就需要使用 REPEATABLE READ 隔离级别来避免。

场景二:不可重复读“不是问题”

业务需求:用户在商品详情页查看库存。我们只需要向用户展示“当前”最新的库存数量即可。
执行流程(同样在 READ COMMITTED 隔离级别下):

  1. 用户请求:应用服务器开启一个事务(或者直接用自动提交的语句),查询商品1的库存。
    START TRANSACTION;
    SELECT stock FROM product WHERE id = 1;  -- 结果:100
    
    页面显示“库存:100件”。
  2. 另一个用户:下单购买1件,事务提交,库存变为99。
  3. 第一个用户:刷新页面,发起了新的请求,应用服务器再次查询库存。
    START TRANSACTION;
    SELECT stock FROM product WHERE id = 1;  -- 结果:99
    
    页面刷新后显示“库存:99件”。

结论:在这个场景下,不可重复读完全不是问题,反而是期望的行为。我们就是希望用户每次刷新都能看到最新的库存数据。如果用 REPEATABLE READ,用户在同一个会话里多次刷新,看到的库存可能一直是旧的(100),直到他关闭浏览器重新打开,这反而体验不好。

2.3 可重复读 RR

可重复读是为了解决并发执行的问题的
启动两个事务,事务A进行update / insert 操作提交,事务B 提交前后分别做一次查询,查看现象:
在这里插入图片描述
可以看到,事务B读取到的数据一直是一致的,这就是可重复读!

但是,一般的数据库在可重复读情况的时候,无法屏蔽其他事务insert的数据(为什么?因为隔离性实现是对数据加锁完成的,而insert待插入的数据因为并不存在,那么一般加锁无法屏蔽这类问题),会造成虽然大部分内容是可重复读的。insert的数据在可重复读情况被读取出来,导致多次查找时,会多查找出来新的记录,就如同产生了幻觉。这种现象,叫做幻读(phantom read)很明显,MySQL在RR级别的时候,是解决了幻读问题的(解决的方式是用Next-Key锁(GAP+行锁)解决的。这块比较难,有兴趣同学了解一下)

2.4 串行化 serializabale

对所有操作全部加锁,进行串行化执行,并发中一定不会有问题,但是只要串行化,效率很低,几乎完全不会被采用!

开启两个事务,事务A进行插入/更新/删除 等操作,事务B执行插入/更新/删除会被阻塞(查询不会阻塞)。只有事务A提交,事务B才会执行操作。

2.5 总结

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

3 事务隔离与数据一致性

一致性不是技术层面的概念,而是一种应用中的方法。

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

相关文章:

  • 国外手表网站湖南省专业建设公司网站
  • php使用腾讯云服务
  • 都安网站建设深圳专业seo优化公司
  • 小尺寸13*13cmRFSOC47DR数模混合信号处理卡
  • 基于PHP开发的医疗安全上报平台——医院不良事件管理系统,规范10大类50多种不良事件的上报、处理和追踪流程
  • Linux 中新建用户
  • bond模式以及配置清单
  • 汽车HIL测试供应商
  • 东方玉色静奢新生|欧神诺中国玉2025秋季新品重磅发布!
  • 织梦dede建站教程视频网站开发入门教程
  • 银川 网站建设郑州做网站 熊掌号
  • 工程实践心得记录-pytorch要安装在哪里
  • 19_AI智能体开发架构搭建之基于Qdrant构建知识库最佳实践指南
  • 零基础学AI大模型之LangChain PyPDFLoader实战与PDF图片提取全解析
  • 拉格朗日对偶法—入门版
  • Docker连接超时的解决方法
  • 显示网站建设精美页面天津外贸公司网站制作
  • JDK 8 到 JDK 24 主要特性对比
  • 数据结构初阶:包装类
  • 4.5数组排序算法
  • 【科普】Edge出问题后如何恢复出厂设置
  • 盲盒一番赏小程序系统开发:重构潮玩消费的沉浸式革命
  • Win10/11 Edge 浏览器收藏夹位置
  • 国外客户的网站电话备案注销网站还有吗
  • 贝叶斯统计结合机器学习在术后院内感染危险因素分析中的应用
  • Spring IOC与DI核心解析
  • 百度网站优化 件阿里云可以做网站
  • [人工智能-大模型-45]:模型层技术 - 大模型的种类、比较、发展趋势
  • Electron 实战|Vue 桌面端开发从入门到上线
  • 【北京迅为】iTOP-4412精英版使用手册-第五十二章 注册字符类设备