Mysql事务
1. 事务定义
- 一个最小的不可再分的工作单元
- 由多个DML语句联合完成(insert、update、delete语句)
DML:Data Manipulation Language 数据操作语言 insert、update、delete
DDL:Data Definition Language 数据定义语言 drop create alter
SQL:Structured Query Language 结构化查询语言,是一种特殊目的的编程语言,是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统
1. 事务ACID特性
-
Atomicity
原子性:最小单元,不可分割,事务中的操作要么都成功,要么都不失败。
-
Consistency
一致性:事务前后数据的完整性必须保持一致。
例:银行转账操作完成后,两人账户总金额不变,转出方正确扣除转账金额,转入方正确增加相同金额
-
Isolation
隔离性:多个事务之间不会相互影响,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
-
Durability
持久性:事务完成后造成的影响是持久性的,接下来即使数据库发生故障也不应该对其有任何影响
2. 事务的流程
-
开启事务:Start Transaction
SQL:start transaction, begin
-
提交事务:**Commit **Transaction
SQL:commit
-
回滚事务:**Rollback **Transaction
SQL:rollback
3. 事务的提交与回滚
-
commit
事务的提交,将所有的事务操作从操作历史持久化到硬盘存储
-
rollback
事务的回滚,将操作历史清空,并关闭事务
注:默认情况下使用InnoDB引擎的每次执行单独DML类型的sql,都会开启事务,并且在执行完成后提交事务
4.事务隔离级别
-
读未提交:read uncommitted
未提交事务的数据可以读取到 可能会发生脏读,幻读,虚读
-
读已提交:read committed
已提交事务的数据可以读取到 可避免脏读情况发生,可能会发生幻读,虚读
-
可重复读:repeatable read
已提交事务的数据也不可以读取到 mysql默认隔离级别,可避免脏读、虚读情况的发生
-
串行化:serializable
可以避免所有的问题,但是效率极低
-
脏读:可以读取到其他事务未提交的数据
-
不可重复读(虚读):指一个线程中的事务读取到了另外一个线程中事务提交的update的数据。
-
幻读:指一个线程中的事务读取到了另外一个线程中事务提交的insert的数据。
InnoDB幻读(使用当前读时):
read view(或者说 MVCC)实现了一致性不锁定读(Consistent Nonlocking Reads),从而避免了(非当前读下)幻读。事务1开始时创建快照,事务2开始于事务1之后,事务2所进行的任何操作(insert,delete,update)都不会影响到快照,从而避免了insert时的幻读。
但是在一定条件下幻读仍然会发生,事务1中若进行update操作(当前读操作),事务2insert的数据 版本会被修改为事务1的版本,当事务1再进行select操作时,事务2insert的数据会被事务1查询到,产生幻读。
针对当前读,RR隔离级别保证对读取到的记录加锁 (记录锁),同时保证对读取的范围加锁,新的满足查询条件的记录不能够插入 (间隙锁),不存在幻读现象。
-
2. Mysql事务处理
1. LBCC
基于锁的并发控制,英文全称Lock Based Concurrency Control。
2. MVCC
多版本的并发控制,英文全称:Multi Version Concurrency Control。
MVCC 在mysql 中的实现依赖的是 undo log 与 read view 。
1)undo log
-
insert undo log
因为 insert 操作的记录只对事务本身可见,对于其它事务此记录是不可见的,所以 insert undo log 可以在事务提交后直接删除而不需要进行 purge 操作。
-
update undo log
update undo log是指在delete和update操作中产生的undo log。该undo log会被后续用于MVCC当中,因此不能提交的时候删除。提交后会放入undo log的链表,等待purge线程进行最后的删除。
2) read view
- m_ids
- m_up_limit_id:m_ids事务列表中的最小事务id,如果当前列表为空那么就等于m_low_limit_id。事务id的下限。
- m_low_limit_id:系统中将要产生的下一个事务id的值。事务id的上限。
- m_creator_trx_id:当前事务id,m_ids中不包含当前事务id。
原理
RC
每次读取数据前都生成一个ReadView
RR
在事务开始后第一次读取数据时生成一个ReadView
RC,RR的区别就在于,当当前事务开始之后,事务2修改数据并且提交,对于RC来说是可见的。因为事务2提交之后,不存在于RC下一次查询生成的的m_ids列表中,所以根据read_view的规则,版本链中事务2的修改是可见的。即,读取到了已提交事务修改的数据。
对于RR来说,事务开始后第一次查询执行生成read_view, 事务2修改并且提交,此时要么事务2的事务id在m_ids列表中,要么事务的事务id大于m_low_limit_id,大于上限,这两种情况下,修改的版本链都是对于当前事务不可见的。所以,当前事务的每次select都见到的是版本链中的同一个版本。即,保证了事务每次读取的都是相同的数据。
3)MVCC的读操作
-
当前读
特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁。 加行写锁 读当前版本。
-
快照读
简单的select操作,属于快照读,不加锁。不加读锁 读历史版本。