MySQL 事务
事务
MySQL 事务主要用于处理操作量大, 复杂度高的数据。比如说, 在人员管理系统中, 你删除一个人员, 你既需要删除人员的基本资料, 也要删除和该人员相关的信息, 如信箱, 文章等等, 这样, 这些数据库操作语句就构成一个事务!
在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。
事务处理可以用来维护数据库的完整性, 保证成批的 SQL 语句要么全部执行, 要么全部不执行。
事务用来管理 insert,update,delete 语句
一般来说, 事务是必须满足4个条件(ACID):
- 原子性(Atomicity, 或称不可分割性)、
- 一致性(Consistency)、
- 隔离性(Isolation, 又称独立性)、
- 持久性(Durability)。
原子性:一个事务(transaction)中的所有操作, 要么全部完成, 要么全部不完成, 不会结束在中间某个环节。事务在执行过程中发生错误, 会被回滚(Rollback)到事务开始前的状态, 就像这个事务从来没有执行过一样。
一致性:在事务开始之前和事务结束以后, 数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则, 这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力, 隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别, 包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
持久性:事务处理结束后, 对数据的修改就是永久的, 即便系统故障也不会丢失。
并发事务带来的问题
事务隔离级别
Read uncommitted 读未提交
Read committed 读已提交
Repeatable read 可重复读
Serializable 串行化
InnoDB 默认的隔离级别是 Repeatable read;
查看事务隔离级别
show variables like "tx_isolation";
mysql 版本 >= 8.0
select @@transaction_isolation;
set session transaction isolation level serializable;
事务隔离多版本并发控制 MVCC
MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能, 用更好的方式去处理读-写冲突, 做到即使有读写冲突时, 也能做到不加锁, 非阻塞并发读
-
快照读
像不加锁的select操作就是快照读, 即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别, 串行级别下的快照读会退化成当前读;之所以出现快照读的情况, 是基于提高并发性能的考虑, 快照读的实现是基于多版本并发控制, 即MVCC,可以认为MVCC是行锁的一个变种, 但它在很多情况下, 避免了加锁操作, 降低了开销;既然是基于多版本, 即快照读可能读到的并不一定是数据的最新版本, 而有可能是之前的历史版本
说白了MVCC就是为了实现读-写冲突不加锁, 而这个读指的就是快照读, 而非当前读, 当前读实际上是一种加锁的操作, 是悲观锁的实现
在Mysql的InnoDB引擎中就是指在已提交读(READ COMMITTD)和可重复读(REPEATABLE READ)这两种隔离级别下的事务对于SELECT操作会访问版本链中的记录的过程。
这就使得别的事务可以修改这条记录, 反正每次修改都会在版本链中记录。SELECT可以去版本链中拿记录, 这就实现了读-写, 写-读的并发执行, 提升了系统的性能
版本链
在InnoDB引擎表中, 它的聚簇索引记录中有两个必要的隐藏列:
trx_id
这个id用来存储的每次对某条聚簇索引记录进行修改的时候的事务id。
roll_pointer
每次对哪条聚簇索引记录有修改的时候, 都会把老版本写入undo日志中。这个roll_pointer就是存了一个指针, 它指向这条聚簇索引记录的上一个版本的位置, 通过它来获得上一个版本的记录信息。(注意插入操作的undo日志没有这个属性, 因为它没有老版本)