目录
1.事务;
1.事务:
1.1 如果CURD不加限制会这么样子?
可能造成数据同时被修改, 数据修改的结果是未知的.(可以想一下之前的抢票线程问题)
1.2 事务概念:
事务就是一组DML语句组成,这些语句在逻辑上存在相关性,这一组DML语句要么全部成功,要么全部 失败,是一个整体. 事务也是你要处理的一个事情, 包含多条mysql语句.
1.3 事务属性: (ACID)
(1) 原子性; 要么全部成功, 要么全部失败, 只有这两种状态.
(2) 隔离性; 防止多个事务并发执行时由于交叉执行而导致数据的不一致。
(3) 持久性; 对数据的修改是持久的.
(4) 一致性; 事务开始之前和事务结束以后,数据库的完整性没有被破坏。
1.4 为什么会出现事务:
目的: 为了让应用层服务.
1.5 事务版本的支持:
只有InoDB支持事务, MySIAM不支持.
1.6 事务提交的方式:
(1) 自动提交;
(2) 手动提交:
⭐查看事务提交方式:
show variables like 'autocommit';
关闭事务自动提交/打开:
set autocommit=0/1;
1.7 事务的常见操作方式:
(1) 开始事务: start transaction; begin;
(2) 创建保持点: savepoint 名称;
(3) 回滚保存点: rollback to 保存点;
(4) 异常终止事务: ctrl+\;
(1) 证明未commit,客户端崩溃,隔离级别设置为读未提交,MySQL自动会回滚;
(2) 证明commit了,客户端崩溃,MySQL数据不会在受影响,已经持久化;
(3) 证明begin操作会自动更改提交方式,不会受MySQL是否自动提交影响
(4) 证明单条 SQL 与事务的关系:
结论:
a. 只要输入begin或者start transaction , 事务便必须要通过commit提交,才会持久化,与是 否设置set autocommit无关。
b. 事务可以手动回滚,同时,当操作异常,MySQL会自动回滚;
c. 对于 InnoDB 每一条 SQL 语言都默认封装成事务,自动提交。
d. 可以看出事务具有原子性和持久性;
⭐a. 如果没有设置保存点,也可以回滚,只能回滚到事务的开始。直接使用 rollback(前提是事务 还没有提交), 设置了就可以选择回退到保持点.
b. 一个事务被提交了(commit),则不可以回退(rollback)
1.8 事务的隔离级别:
隔离性: 就比如学校的学长和你找工作的例子, 学长找工作的经历你可以找到, 但是学长对于你找工作的经历可以不知道, 因为学长以及毕业了. 为了数据不受到干扰就选择了隔离性.
隔离级别:
(1) 读并提交: 所有的事务都可以看到其他事务没有提交的执行结果, 没有隔离性.
(2) 读提交: 大多数数据库的默认的隔离级别, 一个事务只能看到其他的已经提交的事务所做的改变。这种隔离级别会引起不可重复读即一个事务执行时如果多次 select可能得到不同的结果。
(3) 可重复读: 它确保同一个事务,在执行 中,多次读取操作数据时,会看到同样的数据行。但是会有幻读问题.
(4) 串行化:最高隔离级别,它通过强制事务排序,使之不可能相互冲突, 从而解决了幻读的问题。它在每个读的数据行上面加上共享锁,但是可能会导致超时和锁竞争.
隔离级别如何实现: 实现不同的锁.
1.9 查看与设置隔离性:
(1) 查看全局隔离级别:
select @@global.tx_isolation;
(2) 查看当前会话隔离级别:
select @@session.tx_isolation;
(3) 查看局部隔离级别:
select @@tx_isolation;
(4) 设置隔离级别:
语法: set [session/ global] transaction isolation level [read uncommited / read commited / repeatable read/ serializable];
修改之后一般要退出出现查看才会显示新的隔离级别.
(1) 读未提交: [Read Uncommitted]
读取到一个事务还没有commit的数据;
脏读: 一个事务在执行中,读到另一个执行中事务的更新(或其他操作)但是未commit的数据.
(2) 读提交: [Read Committed]
只允许一个查看表数据进行修改, 另外一方在提交之前也看不到提交之后的结果.
不可重复读: 在同一个事务, 不同时间段读取不一样的数据.
(3) 可重复读: [Repeatable Read]
当一个事务完成提交之后, 以及另外一个事务进行查看是看不到更新的数据,只有另外一个事务提交了才可以看到. 解决了幻读(一个数据查看多种情况), 使用了锁.
(4) 串行化: [serializable]
一个事务还没提交之前, 另外一个事务是无法进行修改数据的. 只能等待一个事务提交之后才可以.
总结:
a 隔离级别越严格,安全性越高,但数据库的并发性能也就越低;
b. 不可重复读是数据进行修改; 幻读是数据进行新增.
c. mysql 默认是可重复读;
1.10 一致性:
事务执行的结果,必须使数据库从一个一致性状态,变到另一个一致性状态。当数据库只包含事务 成功提交的结果时,数据库处于一致性状态。如果系统运行发生中断,某个事务尚未完成而被迫中 断,而改未完成的事务对数据库所做的修改已被写入数据库,此时数据库就处于一种不正确(不一 致)的状态。因此一致性是通过原子性来保证的。 其实一致性和用户的业务逻辑强相关,一般MySQL提供技术支持,但是一致性还是要用户业务逻辑 做支撑,也就是,一致性,是由用户决定的。
1.11 深入理解隔离性:
数据并发的场景包括:
读读: 不会发生线程安全问题;
读写: 会发生线程安全问题, 可能出现脏读, 幻读, 不可重复读;
写写: 会发生线程安全问题, 可能存在更新数据丢失.
(1) 读写:
解决上诉问题: 多版本并发控制(MVCC), 是一种读写冲突的无锁并发控制.
a. 3个记录隐藏列字段:
DB_TRX_ID: 最近修改的事务ID(6byte);
DB_ROLL_PTR: 回滚指针, 指向上一个版本(7byte);
DB_ROW_ID: 隐藏自增id(隐藏主键);
删除flag隐藏字段: 并不是删除了, 而是删除flag变了.
b. undo 日志:
MySQL 中的一段内存缓冲区,用来保存日志数据;
c. MVCC操作:
首先进行对事物加锁; 修改前将数据拷贝到undo log(写时拷贝); 修改原始数据, 以及隐藏字段 DB_TRX_ID, 还有DB_ROLL_PTR 列, 写入undo log的地址; 提交事务,释放锁.
快照: 一个个历史版本; 当前读: 读取最新的数据;
select 读取的是历史版本;
1.12 Read View:
读视图: 记录并维护系统当前活跃事务的ID;
本质: 结构体, 类;
主要内容:
class ReadView {// 省略...private:/** 高水位,大于等于这个ID的事务均不可见*/trx_id_t m_low_limit_id /** 低水位:小于这个ID的事务均可见 */trx_id_t m_up_limit_id;/** 创建该 Read View 的事务ID*/trx_id_t m_creator_trx_id;/** 创建视图时的活跃事务id列表*/ids_t m_ids;/** 配合purge,标识该视图不需要小于m_low_limit_no的UNDO LOG,* 如果其他视图也不需要,则可以删除小于m_low_limit_no的UNDO LOG*/trx_id_t m_low_limit_no;/** 标记视图是否被关闭*/bool m_closed;// 省略... };
其中 m_ids 用来维护读视图的生成时刻以及活跃事务id.
up_limit_id 记录事务中最小id,
low_limit_id: 成时刻系统尚未分配的下一个事务ID,也就是目前已出现过的事务ID的最大值+1
creator_trx_id: 创建该事务的id.
1.13 RR 与 RC的本质区别⭐:
(1) Read View生成时机的不同,从而造成RC,RR级别下快照读的结果的不同;
(2) 在RR级别下第一次快照读会创建一个快照及Read View, 调用快照读使用的是同一个read view, 对之后的修改不可见到; 早于Read View创建的事务所做的修改均是可见.
(3) RC级别下的,事务中,每次快照读都会新生成一个快照和Read View, 这就是我们在RC级别下 的事务中可以看到别的事务提交的更新的原因.
(4) RC每次快照读,都会形成Read View,所以,RC才会有不可重复读问题;