----《Hello MySQL!》(7))
文章目录前言事务的概念事务的版本支持事务的提交方式手动提交事务的隔离级别查看和设置隔离级别更深层次的理解隔离性理解MVCC作业部分前言事务是 MySQL 保证数据一致性的核心机制也是后端开发、面试的高频考点。但实际开发中很多人只会简单使用事务却不懂 ACID 的真正含义、分不清隔离级别的适用场景、不理解 MVCC 的工作原理导致事务提交踩坑、数据错乱、并发异常。本文不讲冗余理论只聚焦实战与核心涵盖 MySQL 事务的概念、ACID 四大属性详解事务的版本支持、提交方式自动 / 手动、保存点与回滚操作拆解四种隔离级别的差异及对应的并发问题脏读 / 幻读等深入讲解 MVCC 多版本并发控制的核心逻辑附带经典作业解析帮你快速掌握事务管理的核心用法避开常见误区确保并发场景下数据一致。事务的概念事务就是一组DML语句组成这些语句在逻辑上存在相关性这一组DML语句要么全部成功要么全部失败是一个整体事务需要具有4个属性:简称ACID原子性(不可分割性)(automicity)一致性(consistency):事务执行的结果必须使数据库从一个一致性状态变到另一个一致性状态技术上是通过AID保证的C隔离性(又称独立性)(isolation)持久性(durability):事务处理结束后对数据的修改是永久的即使系统故障也不会丢失事务的版本支持查看方法:show engines \G注意:不是所有的引擎都支持事务的引申:\G是大小写敏感的!事务的提交方式查看事务的提交方式:show variables like autocommit;on就表示自动提交(也就是autocommit)开着注意:InnoDB支持事务,MyISAM不支持事务修改事务提交方式的方法:(这个是会话级的修改退出当前mysql会话就没了)set autocommit0;设置成禁止自动提交set autocommit1;设置成开始自动提交注意:需要重启mysql客服端才会生效关于单条SQL语句跟事务的关系:在自动提交开启时单条SQL语句其实就是一个事务,并且这个事务会立马自动提交手动提交需要用begin手动开启一个事务commit来提交一个事务begin;//开启事务--或者用start transaction savepoint a;//设置一个保存点--名字叫a 保存点可以设置多个 rollback to a;//回滚到保存点a处--保存点到这的操作都会被抹除这些操作都会失去作用 rollback;//直接回滚到开始事务的最初状态,并关闭事务 commit;//提交这个事务,事务自动关闭注意:如果一个事务已经提交了就不能rollback了对异常情况的分析:1.还没有commit客户端就崩溃了MySQL会自动回滚到上一个commit2.已经commit了客户端崩溃MySQL的数据不会受影响–因为持久化了3.如果本来是自动提交但是手动启动事务的话还是需要手动commit才行事务的隔离级别数据库中为了保证事务执行过程中尽量不受干扰–隔离性数据库中允许事务受不同程度的干扰–隔离级别隔离级别有四种:读未提交Read uncommitted 简称RU:所有的事务都可以看到其他事务没有提交的执行结果,会引发很多问题:不可重复读脏读幻读读提交(Read committed 简称RC):一个事务只能看到其他的已经提交的事务所做的改变会引起不可重复读,幻读问题可重复读(Repeatable read 简称RR):一个事务里反复读某条数据不管中间有没有其他事务改了这数据这条数据都不会受其他事务的影响会引起比如幻读的问题–想收到其他事务的提交的话必须要自己这个事务结束–引申:在RR级别下多个修改操作的话也是会加锁的串行化(serializable):这个是事务的最高隔离级别。在每个读的数据行上面加上共享锁来强制事务排序从而避免相互冲突–但是可能会导致超时和锁竞争–如果几个事务是读操作的话是可以同时进行的大多数数据库的默认隔离级别是读提交MySQL的默认隔离级别是可重复读引申:事务在进行增删改操作时都会偷偷的进行读取数据的脏读:一个事务在执行中读取到其他未提交事务的操作结果不可重复读:一个事务在不同时间读取到的结果不同–这是个问题,比如:先读取月薪3k的再读取月薪4k的可能有人工资在这个期间被修改了那这个人就出现了两次了幻读:大多数情况是因为隔离不了insert插入数据导致的–隔离不了insert的原因:没有历史版本可以被锁定查看和设置隔离级别查看全局的隔离级别:select global.tx_isolation;查看会话(当前)的隔离级别:select session.tx_isolation;或者select tx_isolation;设置隔离级别的语法:set[session|global]transaction isolation level{read uncommitted|readcommitted|repeatableread|serializable};[session|global]如果不选的话默认是session{}里面那个是多选一 eg:set session transaction isolation levelreadcommitted;引申:如果修改了全局的话重新连接会话会话就变成现在全局的这个了当前会话跟全局的隔离级别不一样的话会以当前会话的隔离级别为准注意:改隔离级别一般是选择改全局的–一般是要求隔离级别都一样会好些更深层次的理解隔离性数据库并发控制用的是MVCC(多版本并发控制)–处理读-写和写-写的并发问题MVCC是一种用来解决读-写冲突的无锁并发控制–为事务分配事务ID给每个修改操作都保存一个版本;读操作就是读这个事务开始前的快照引申:事务ID是单增的理解MVCC前置知识引入:3个记录隐藏列(隐藏字段)undo日志Read View3个记录隐藏列:DB_TRX_ID:记录创建这条记录/最后一次修改该记录的事务IDDB_ROLL_PTR:回滚指针指向这条记录的上一个版本DB_ROW_ID:隐含的自增ID(即隐藏主键)–如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引如果不知道的话会默认设置成null引申:还有一个删除flag隐藏字段, 记录这个数据是不是被deleteundo日志:就是MySQL中一段内存缓冲区用来保存日志数据–事务提交之后那个事务对应的在undo日志里的数据会被标记为可回收(等其他事务的快照不用他了就会被清理)单条数据的多版本链:(基于链表形成的历史版本链)在修改之前上一条数据会在undo log里面形成一个副本(地址是0x18181818),修改是在非副本的那条数据上直接进行的修改–update和delete可以形成版本链insert先不考虑delete的话就是给这个数据的隐藏列打上一个已删除的标记回滚其实就是用历史的数据去覆盖当前的数据(回滚回去了就不会回滚回来了)事务在执行快照读时会生成数据库当前的一个快照快照读(也就是读取历史版本):比如在读已提交下每次select会触发快照读只有读已提交和可重复读才会有快照读写-写并发的话都理解成是当前读(读取数据的最新版本)Read View:事务进行快照读操作的时候产生的读视图,是一个类里面主要有:m_ids–一张列表–维护这个读视图生成时系统正常执行的事务IDup_limit_id–记录m_ids列表中事务ID最小的IDlow_limit_id记录读视图生成时系统没有分配的最小的事务IDcreator_trx_id创建改读视图的事务ID快照就是记录快照时数据库里面数据当时的版本Read View是实现快照这个功能的核心–看DB_TRX_ID跟Read View中那几个变量的关系来判断应该看到这个数据的哪个版本作业部分设有两个事务T1,T2,其并发操作如下所示,下面评价正确的是DA.该操作不能重复读B.该操作不存在问题C.该操作读脏数据D.该操作丢失修改