数据库相关
事务:
概念
事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态到另一种一致性状态。事务是逻辑上的一组操作,要么都执行,要么都不执行。
MySQL默认就是自动事务管理(自动开启事务,自动提交事务),一条sql语句就是一个事务
事务执行的过程中,若无异常,则会commit完成curd,若出现异常,则会rollback回滚到事务回滚点
四大特性(ACID)
- 原子性(Atomicity):事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
- 一致性(Consistency):事务前后数据的完整性必须保持一致。
- 隔离性(Durability):事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
- 持久性(Isolation):多个用户并发操作数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。即事务之间互不干扰。
事务隔离级别:
为了达到事务的四大特性,数据库定义了4种不同的事务隔离级别,由低到高依次为Read uncommitted、Read committed、Repeatable read、Serializable,这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题。
脏读:事务A读到了事务B还未commit的内容,事务B若rollback,则事务A读到了不存在的内容即为脏读。
不可重复读:事务A在两次读取同一数据的过程中,若该数据在此期间被事务B修改,则事务A读取的同一数据内容不同,则为不可重复读。
幻读:事务A在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行(如事务B在此期间插入了一条数据)。
个人理解:幻读与不可重复读的区别是,幻读注重范围查和并发增,不可重复读注重重复读和并发改
| 级别 | 名字 | 隔离级别 | 脏读 | 不可重复读 | 幻读 | 数据库默认隔离级别 |
|---|---|---|---|---|---|---|
| 1 | 读未提交 | read uncommitted | 是 | 是 | 是 | |
| 2 | 读已提交 | read committed | 否 | 是 | 是 | Oracle |
| 3 | 可重复读 | repeatable read | 否 | 否 | 是 | MySQL |
| 4 | 串行化 | serializable | 否 | 否 | 否 |
- READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
- READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
- REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生(当前读)。
- SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
需注意:
- InnoDB 存储引擎默认使用 **REPEATABLE-READ(可重读)**
- InnoDB 存储引擎在 分布式事务 的情况下一般会用到**SERIALIZABLE(可串行化)**隔离级别。
MVCC:
当前读和快照读:
MVCC属于快照读,即普通的select语句
当前读即每次读取最新数据,需要利用锁机制来实现,常见sql语句如下:
- select lock in share mode(共享锁)
- select for update(排他锁)
- update(排他锁)
- insert(排他锁)
- delete(排他锁)
实现原理:
MVCC 没有正式的标准,所以在不同的 数据库管理系统(DBMS) 中,MVCC 的实现方式可能是不同的。
mvcc的实现,基于undolog、版本链、readview。

在mysql存储的数据中,除了我们显式定义的字段,mysql会隐含的帮我们定义几个字段。
-
trx_id:事务id,每进行一次事务操作,就会自增1。
-
roll_pointer:回滚指针,用于找到上一个版本的数据,结合undolog进行回滚。
mvcc所提到的读是快照读,也就是普通的select语句。快照读在读写时不用加锁,不过可能会读到历史数据。
readview:
readview即快照,事务中每个select读前会生成一个readview。快照是用来获取当前事务能够读取版本的字段集,包含以下字段:
-
m_ids:当前活跃的事务id列表。活跃的事务就是指还没有commit的事务。
-
max_trx_id:下一个活跃事务将被分配的id值。例如m_ids中的事务id为(1,2,3),那么下一个应该分配的事务id就是4,max_trx_id就是4。
- min_trx_id:活跃事务中的最小事务id,即min(m_ids)。
-
creator_trx_id:当前readview的事务id。
由上可知,若trx ∈ m_ids,则min_trx_id <= trx <= max_trx_id
若trx == creator_trx_id 或 trx < min_trx_id 或 trx!=m_ids,则trx版本可以被当前事务访问
MVCC对RC和RR事务隔离级别的实现:
RC:每个快照读都会生成并获取最新的readview,即选择可选取的最大的trx
RR:有在同一个事务的第一个快照读才会创建readview,之后的每次快照读都使用的同一个readview,所以每次的查询结果都是一样的。
需注意:
- 仅作MVCC的快照读时不会产生幻读
- innodb的RR级别,当前读时,通过使用where给定区间(select...from...where... for update)则不止会加行锁(record lock),还有间隙锁(gap),即next-key锁(行锁+gap锁),这种锁会解决绝大部分幻读问题。若仅仅只有select for update,则还是会产生幻读。
参考文章:https://blog.csdn.net/m0_49790240/article/details/123775697?spm=1001.2014.3001.5506
https://blog.csdn.net/lans_g/article/details/124232192