Mysql-事务(Transaction)详解
什么是事务?
事务(Transaction),就是将一组SQL语句放在同一批次内去执行,如果一个SQL语句出错,则该批次内的所有SQL都将被取消执行。
特点:
一个事务中如果有一个数据库操作失败,那么整个数据库的所有操作都会失败,数据库数据就会回滚到该事务开始之前的状态。
限制:
MySQL数据库中仅InnoDB和BDB类型的数据库表支持事务。
事务的ACID原则
1. 原子性(Atomic)
意味着数据库中的事务执行是作为原子粒度。即不可再分,整个语句要么执行,要么不执行。
2. 一致性(Consist)
即在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
3. 隔离型(Isolated)
事务的执行是互不干扰的,一个事务不可能看到其他事务运行时,中间某一时刻的数据。
4. 持久性(Durable)
意味着在事务完成以后 ,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
Mysql事务实现
方法
START TRANSACTION
:开始一个事务,标记事务的起始点SET AUTOCOMMIT
:使用该语句来改变自动提交模式,等于0时关闭自动提交模式,等于1时开启自动提交模式。默认为1,使用事务时为0COMMIT
:提交一个事务给数据库ROLLBACK
:将事务回滚,数据回到本次事务的初始状态
步骤
- 关闭MySQL自动提交:
SET AUTOCOMMIT = 0
- 开启一个事务,标记事务的起始点:
START TRANSACTION;
- 提交或者回滚(只能存在其一)
-
- 提交:
COMMIT
- 回滚:
ROLLBACK
- 提交:
- 开启MySQL自动提交:
SET AUTOCOMMIT = 1
事务的原子性,一致性,持久性
事务的原子性、一致性和持久性由事务的 redo 日志和undo 日志来保证。
- REDO LOG :称为 重做日志 ,提供再写入操作,恢复提交事务修改的页操作,用来保证事务的持久性。
- UNDO LOG :称为 回滚日志 ,回滚行记录到某个特定版本,用来保证事务的原子性、一致性
事务的隔离性
事务的隔离性是指为了让不同的事务之间相互不存在干扰,就需要对事务的操作进行隔离,事务的隔离性也就是将操作同一个数据的事务相互分离,让操作之间分开有序的执行。
用什么方式实现事务的隔离性
通常数据库里都是采用锁的机制,保证事务之间的隔离性
Mysql中的锁
表级锁(Table Locks)
表级锁是锁定整个表的锁。这种锁开销较小,但并发性较差。表级锁分为两类:
- 表共享读锁(Table Read Lock, S锁): 允许其他事务读取,但不允许写入
- 表独占写锁(Table Write Lock, X锁): 不允许其他事务读取和写入
行级锁(Row Locks)
行级锁是锁定表中的具体行。这种锁开销较大,但并发性好。行级锁在InnoDB存储引擎中最为常见,并分为两类:
- 共享锁(Shared Lock, S锁):允许事务读取一行,但不允许修改。
- 排他锁(Exclusive Lock, X锁):允许事务读取和修改一行。
全局锁(Global Locks):
全局锁用于锁定整个数据库实例,通常用于备份。MySQL提供了FLUSH TABLES WITH READ LOCK (FTWRL)
命令来实现全局锁。
元数据锁(Meta-data Lock, MDL)
MDL用于保护表的元数据不被并发修改。当一个事务正在访问表元数据(如修改表结构)时,其他事务必须等待,以确保元数据的一致性。
意向锁(Intention Lock)
意向锁是一种表级锁,表示事务希望在表中的某些行上设置行级锁。意向锁分为两类:
- 意向共享锁(Intention Shared Lock, IS锁):表示事务准备设置共享锁。
- 意向排他锁(Intention Exclusive Lock, IX锁):表示事务准备设置排他锁。
记录锁(Record Lock)
记录锁是行级锁的一种,锁定索引记录。
间隙锁(Gap Lock)
间隙锁锁定索引记录之间的间隙,防止其他事务在这些间隙中插入新记录。主要用于防止幻读现象。
临键锁(Next-Key Lock)
临键锁是记录锁和间隙锁的组合,锁定索引记录及其前面的间隙。这种锁在InnoDB的可重复读(REPEATABLE READ)隔离级别下用于防止幻读。
插入意向锁(Insert Intention Lock)
插入意向锁是一种特殊的间隙锁,用于在间隙中插入新记录。多个事务可以在同一个间隙中持有插入意向锁,而不会互相阻塞。
事务并发时出现的问题
1. 脏写
当两个或多个事务同时修改同一数据时,后提交的事务可能会覆盖前一个事务所做的修改,导致前一个事务的更新被丢失。
2. 脏读(可重复读)
一个事务读取了另一个事务尚未提交的数据。如果后续这个事务被回滚,那么读取到的数据就是无效的。
3. 不可重复读
在同一个事务中,两次读取同一行数据得到的结果不一致。
- 并发事务更新:当一个事务在读取数据后,另一个事务对同一行数据进行了更新操作。
- 并发事务删除:当一个事务在读取数据后,另一个事务对同一行数据进行了删除操作。
4. 幻读
在同一个事务中,两次查询相同条件的数据得到的结果集不一致。
- 并发事务插入:当一个事务在查询数据后,另一个事务对相同的条件的数据进行了插入操作。
- 并发事务删除:当一个事务在查询数据后,另一个事务对相同的条件的数据进行了删除操作。
- 并发事务更新:当一个事务在查询数据后,另一个事务对相同条件的数据进行了更新操作。
事务的隔离级别
1. 读未提交:
- 事务读取:不加锁
- 事务写入:加写锁
- 解决问题:脏写
- 存在问题:脏读,不可重复读,幻读
2. 读提交(不可重复读):
- 事务读取:加读锁(每次select完释放读锁)
- 事务写入:加写锁
- 解决问题:脏写,脏读
- 存在问题:不可重复读,幻读
3. 可重复读:
- 事务读取:加读锁(每次select完不释放锁,而是事务结束后才释放)(如果是mysql的InnoDB还会加间隙锁)
- 事务写入:加写锁
- 解决问题:脏写,脏读,不可重复读
- 存在问题:幻读(InnoDB不存在幻读)
4. 串行化:
事务之间没有影响,不管读取还是修改事务,串行化执行,一个事务执行必须等其他事务结束
InnoDB的MVCC
MVCC 的实现依赖于:隐藏字段(版本号)、Undo Log、Read View。
MVCC (Multiversion Concurrency Control),多版本并发控制。顾名思义,MVCC 是通过数据行的多个版本管理来实现数据库的 并发控制 。这项技术使得在InnoDB的事务隔离级别下执行 一致性读 操作有了保证。换言之,就是为了查询一些正在被另一个事务更新的行,并且可以看到它们被更新之前的值,这样 在做查询的时候就不用等待另一个事务释放锁。
InnoDB就是通过MVCC机制解决可重复读中的幻读问题