事务 ---- mysql

一. 引出事务

在日常开发中, 很多操作不是通过一个SQL完成的, 往往需要多个SQL配合完成

但是当多个SQL操作时, 如果中间出现了特殊的情况(程序崩溃, 系统崩溃, 网络断开, 主机掉电......), 那么可能就会出现, 前面的SQL执行成功, 后面的SQL执行失败了

考虑一个场景: 转账

如果a要给b转账500, 那么a的余额-500, b的余额+500, 那么如果在a的余额-500之后, 就出现了上述的特殊情况, 那么这个钱就消失了

这个时候就要使用到事务

二. 概念

事务, 指把多个操作, 打包成一个整体, 就能够保证, 这个整体要么都执行成功, 要么就一个都不执行, 有效避免, 部分执行, 部分未执行, 产生的一些"中间状态引起的问题"
其实, 如果中间出现问题, 并不是真的一个都没有执行, 事务中的若干个SQL必然是要一条一条执行的, 但是事务能够保证, 当执行到某一条的时候如果出现问题了, 数据库就能够自动把前面的sql造成的影响, 给恢复回去, 恢复完成, 看起来就好像一条sql都没执行的样子
像这样的"翻新"操作, 称为**"回滚"(rollback)**
为了实现回滚机制, 数据路在执行事务的时候, 记录日志
(数据库的日志是写入到硬盘的文件中)
当事务最终都执行完毕, 中间没有差错, 那么这些记录内容就可以不要了
但是如果执行事务的过程中, 出现问题了, mysql就可以根据日志中记录的内容, 来进行恢复操作
1)之前进行了新增操作, 就把数据删除掉
2)之前进行了删除操作, 就把数据新增回来
3)之前进行了修改操作, 就把数据改回去
4)之前进行了查询操作, 不需要任何恢复行为

三. 事务的基本特性

1. 原子性
上述把多个操作打包成一个整体, 有回滚机制, 能够出发还原的这种特性, 称为"原子性"
2. 一致性
执行事务之前和执行事务完毕之后, 数据是一致的, 不会出现对不上的情况, 其实和回滚是有关的, 一旦触发回滚了, 回滚回去的数据得是对的, 如果顺利执行没有触发回滚, 数据也是符合要求的
3. 持久性
但凡提到持久性, 就要想要: 把数据存储在硬盘上
此处的持久, 指的是程序重启/主机重启, 数据仍然存在
执行事务产生的修改, 会在硬盘上持久保存
4. 隔离性
隔离性主要考虑的是, 数据库并发执行事务时, 产生的情况
并发是指: 多个客户端, 同时给服务器, 发起事务,
此时就需要数据库服务区都能够给处理
如果同时处理, 又可能会出现问题:
1) 脏读问题
数据库中, 如果有事务A和事务B, 事务A针对某个表做出了一些修改, 但是在事务A提交之前(即事务完毕之前), 事务B就对这里的数据进行了读取, 最终就可能出现A后续的操作又把上述数据进行了修改, 导致最终B读到的数据和A提交的数据是不同的, 于是就出现了"脏读问题"
为了避免这样的情况出现, 我们可以针对 "写操作"加锁
本来是执行事务A的时候, B事务可以执行, 但是引入写加锁后, 执行A的过程中, B就不能执行了, 要等待
但是这样就相当于降低了"并发能力", 也就会降低数据库服务器的处理效率, 同时提高了"隔离性", 也提高了数据库的准确性
并发执行事务的过程中, 相互之间影响越小, 隔离性就越高, 影响越大, 隔离性就越低
2) 不可重复读问题
存在三个事务ABC, 事务A针对数据进行修改, 提交, 接下来事务B进行读取数据, 在B执行的过程中, 又有一个事务C, 又针对数据进行修改, 而此时事务B还在对数据进行读取, 就会出现前后读取的数据不一致
为了避免这样的情况出现, 我们可以针对" 读操作"加锁
本来是执行事务B的时候, C事务可以执行, 但是引入读加锁后, 执行B的过程中, C就不能执行了, 要等待
同样这样就相当于降低了"并发能力", 也就会降低数据库服务器的处理效率, 同时提高了"隔离性", 也提高了数据库的准确性
3) 幻读问题
事务A先修改并提交了数据, 事务B进行读数据, 此时事务C, 没有修改B读的数据, 但是给对应的表进行了新增数据/删除数据等操作, 导致事务B中, 读到的数据集不同, 就会出现"幻读问题"
解决幻读的方式, 是 "串行化", 时所有的事务都严格的按照"一个接一个"的方式进行, 完全没有并发了
此时执行的效率是最低的, 隔离性也是最高的, 数据也是最准确的
总结一下:
1)脏读 ==> 写加锁
2) 不可重复读 ==> 读加锁
3) 幻读 ==> 串行化
mysql事务的隔离性具体是怎么实现呢? mysql给程序猿提供了四个隔离级别, 可以在mysql配置文件中进行设置

  1. read uncommitted: 允许读取其他事务未提交的数据
  2. read committed: 不允许读取其他事务未提交的数据
  3. repeatable read: 针对读操作和写操作都加锁了
  4. serializable(串行化): 所有事物都是串行执行的
    在实际开发中, 我们要根据具体的应用场景来选择不同的隔离级别

四. 使用事务

  1. 开始事务:
    start transaction;
  2. 回滚或提交:
    rollback/commit;
    例:
sql 复制代码
start transaction;
-- 阿里巴巴账户减少2000
update accout set money=money-2000 where name = '阿里巴巴';
-- 四十大盗账户增加2000
update accout set money=money+2000 where name = '四十大盗';
commit;

中间的SQL语句, 就被打包成一个整体了

相关推荐
崖山数据库系统YashanDB22 分钟前
YashanDB json语法
数据库
陈三一25 分钟前
关于多数据源下Spring声明式事务管理失效问题的分析与解决
数据库·spring
我有医保我先冲1 小时前
SQL复杂查询与性能优化全攻略
数据库·sql·性能优化
烧瓶里的西瓜皮1 小时前
Go语言从零构建SQL数据库引擎(2)
数据库·sql·golang
SelectDB1 小时前
拉卡拉 x Apache Doris:统一金融场景 OLAP 引擎,查询提速 15 倍,资源直降 52%
大数据·数据库·数据分析
爱的叹息1 小时前
华为高斯(GaussDB) 集中式数据库 的开发技术手册,涵盖核心功能、开发流程、优化技巧及常见问题解决方案
数据库·gaussdb
背太阳的牧羊人2 小时前
使用 PyMuPDF(fitz)库打开 PDF 文件,并且是从内存中的字节流(BytesIO)读取 PDF 内容
数据库·pdf·文件处理·pymupdf·fitz
@淡 定3 小时前
MySQL MVCC 机制解析
数据库·mysql
Chandler243 小时前
Redis:内存淘汰原则,缓存击穿,缓存穿透,缓存雪崩
数据库·redis·缓存
SRC_BLUE_173 小时前
Python GUI 编程 | QObject 控件基类详解 — 定时器
开发语言·数据库·python