一、含义
一条或多条sql语句组成一个执行单位,一组sql语句要么都执行要么都不执行
二、特点(ACID)
- 原子性:一个事务是不可再分割的整体,要么都执行要么都不执行,基于日志的
Redo/Undo
机制 - 一致性:一个事务的执行不能破坏数据库数据的完整性和一致性
- 隔离性:一个事务不受其它事务的干扰,多个事务是互相隔离的
- 持久性:一个事务一旦提交了,则永久的持久化到本地
原子性、隔离性、持久性都是为了保障一致性而存在的,一致性也是最终的目的
三、分类
1、隐式事务:没有明显的开启和结束,本身就是一条事务可以自动提交,比如insert、update、delete
2、显式事务:具有明显的开启和结束,例如以下格式:
# 1、开启事务
set autocommit=0; #关闭自动提交
start transaction; #开启事务机制
# 2、编写一组逻辑sql语句
注意:sql语句支持的是insert、update、delete
# 【设置回滚点,可选项】
savepoint 回滚点名;
# 3、结束事务
提交:commit;
回滚:rollback;
回滚到指定的地方: rollback to 回滚点名;
# 查看隔离级别
SELECT @@tx_isolation;
# 设置隔离级别 - 分为全局隔离和会话隔离,会话隔离只对当前窗口有效
SET SESSION|GLOBAL TRANSACTION ISOLATION LEVEL 隔离级别;
四、事务并发(读问题)
多个事务同时操作同一个数据库的相同数据时会导致事务的并发问题
- 脏读:该事务读到了另一个事务 未提交的 update 数据
- 不可重复读:读到了另一个事务 提交的 update 数据
- 幻读:该事务读到了另一个事务 提交的 insert 数据
如何解决:通过设置事务的隔离级别( √ 代表解决)
隔离级别 | 隔离描述 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|---|
READ UNCOMMITTED | 读未提交 | × | × | × |
READ COMMITTED | 读已提交(Oracle默认) | √ | × | × |
REPEATABLE READ | 可重复读(MySQL默认) | √ | √ | × |
SERIALIZABLE | 串行化 | √ | √ | √ |
- 读未提交:导致读脏,当前事务可以读取其它事务未提交的数据
- 读已提交:解决读脏,在事务未提交之前所做的 update 其它事务是不可见的,但导致不可重复读
- 可重复读:解决不可重复读,保证当前事务多次相同的查询的结果是一致的,但导致幻读
- 可串行化:解决幻读,可串行化就是保证读取的范围内没有新的数据插入,
读已提交演示图
五、Redo/Undo机制
1、将所有对数据的更新操作都写到日志中
- Redo log:记录数据修改后的值,可以用来恢复未写入 data file 的已成功事务更新的数据
- Undo log:记录数据更新前的值,保证数据更新失败能够回滚
假如数据库在执行的过程中,不小心崩了,可以通过该日志的方式,回滚之前已经执行成功的操作,实现事务的一致性。
具体的实现流程:
假如某个时刻数据库崩溃,在崩溃之前有事务A和事务B在执行,事务A已经提交,而事务B还未提交。当数据库重启进行 crash-recovery 时,就会通过Redo log将已经提交事务的更改写到数据文件,而还没有提交的就通过Undo log进行roll back。
六、Mysql的锁机制
类型 | 说明 |
---|---|
读锁/共享锁(Shared Locks) | 读的时候,加共享锁,不能写 |
写锁/排它锁(Exclusive Locks) | 写的时候,加排它锁,阻塞其它事务的写入和读取 |
间隙锁 | |
行锁(Record Locks) | 增删改时锁当前行,锁的粒度小,加锁慢,锁冲突的概率小,并发度高 |
表锁 | 增删改时锁当前表,锁的粒度大,加锁快,开销小,锁冲突的概率大,并发度低 |
间隙锁分为:
Gap Locks
和Next-Key Locks
- Gap Locks会锁住两个索引之间的区间,比如
select * from User where id>3 and id<5 for update
,就会在区间(3,5)之间加上Gap Locks Next-Key Locks
是Gap Locks+Record Locks形成闭区间锁select * from User where id>=3 and id=<5 for update,就会在区间[3,5]之间加上Next-Key Locks
读未提交是没有加任何锁的,所以对于它来说也就是没有隔离的效果,所以它的性能也是最好的。
串行化加的是一把大锁,读的时候加共享锁,不能写,写的时候,加的是排它锁,阻塞其它事务的写入和读取,若是其它的事务长时间不能写入就会直接报超时,所以它的性能也是最差的,对于它来就没有什么并发性可言。
读提交和可重复读,兼顾解决数据问题,然后又要有一定的并发行,所以在实现上锁机制会比串行化优化很多,提高并发性,所以性能也会比较好。
七、事务底层实现原理 MVCC(多版本并发控制)
实现MVCC时用到了一致性视图,用于支持读提交和可重复读的实现
可重复读:只需要在事务开始的时候创建一致性视图,也叫做快照,之后的查询里都共用这个一致性视图,后续的事务对数据的更改是对当前事务是不可见的,这样就实现了可重复读
读已提交:每一个语句执行前都会重新计算出一个新的视图,这个也是可重复读和读提交在MVCC实现层面上的区别