MySql事务&锁
事务的特点
原子性(Atomicity)
生物钟所有操作作为一个整体像原子一样不可分割,要么全部成功,要么全部失败。一致性(Consistency)
事务的执行结果必须从数据库的一个一致性状态到另一个一致性状态。一致性状态是指:
- 系统的状态满足数据的完整性约束(主码,参照完整性,check约束等)
- 系统的状态反应数据库本应描述的现实世界的真实状态,比如转账前后两个账户的金额总和应该保持不变。
隔离性(Isolation)
并发执行的事务不会相互影响,其对数据库的影响和他们串行执行时一样。比如多个用户同时往一个账户转账,最后账户的结果应该和他们按先后次序转账的结果一样。持久性(Durability)
事务一旦提交,其对数据库的更新就是持久的。任何事务或系统故障都不会导致数据丢失。
- 在事务的四个特点中,一致性时事务的根本追求,而在某些情况下会对事务的一致性造成破坏:
- 事务的并发执行
- 事务故障或系统故障
- 数据库系统通过并发控制技术和日志恢复技术来避免这种情况的发生
- 并发控制技术保证的事务的隔离性,使数据库的一致性状态不会因为并发执行的操作被破坏。
- 日志恢复技术保证了事务的原子性,使一致性状态不会因为事务或系统故障被破坏。同时使已提交的对数据库的修改不会因为系统崩溃而丢失,保证了事务的持久行。
graph LR A[事务] --> B[隔离性] A[事务] --> C[一致性] A[事务] --> D[原子性] A[事务] --> E[持久性] B[隔离性] --> F[并发控制] C[一致性] --> F[并发控制] C[一致性] --> G[日志恢复] D[原子性] --> G[日志恢复] E[持久性] --> G[日志恢复]
事务的实现原理
- 事务的原子性是通过 undo log 来实现的
- 事务的持久性是通过 redo log 来实现的
- 事务的隔离性是通过 (读写锁 + MVCC) 来实现的
- 事务的一致性是通过 原子性、持久性、隔离性 来实现的
原子性实现原理逻辑日志(Undo Log)
- Undo Log是为了实现事务的原子性,在MySql数据库InnoDB存储引擎中,Undo Log是来实现多版本并发控制(简称:MVCC)
- 在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方称为Undo Log)。然后进行数据的修改。如果出现了错误或者用户执行了ROLLBACK语句,系统可以利用Undo Log中的备份将数据恢复到事务开始之前的状态
持久性实现原理(Redo Log)
- 和Undo Log相反,Redo Log记录的是新数据的备份。在事务提交前,只要将Redo Log持久化即可,不需要将数据持久化。当系统崩溃时,虽然数据没有持久化,但是Redo Log已经持久化。系统可以根据Redo Log的内容,将所有数据恢复到最新的状态
MySql的隔离级别
- 事务具有隔离性,理论上来说事务之间的执行不应该相互影响,其对数据库的影响应该和他们串行执行时一样。
- 然而完全的隔离级别会导致系统并发性能很低,降低对资源的利用率,因而实际商队隔离性的要求会有所放宽,这也会一定程度造成对数据库一致性要求降低
- SQL标准为事务定义了不同的隔离级别,从低到高依次是
- 读未提交(READ UNCOMMITTED):对事物处理的读取没有任何限制,不推荐
- 读已提交(READ COMMITTED)
- 可重复读(PEPEATABLE READ)
- 串行化(SERIALLZABLE)
不同的隔离级别可能导致不同的并发异常
事务的隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(READ UNCOMMITTED) | √ | √ | √ |
读已提交(READ COMMITTED) | √ | √ | |
可重复读(PEPEATABLE READ) | √ | ||
串行化(SERIALLZABLE) |
隔离性实现原理:锁
在MySql中,锁可以分为两类:
共享锁:共享锁定是将对象数据变为只读形式,不能进行更新,所以也称为读取锁定;
1
select * from user where id = 1 lock in share mode;
排他锁:排他锁是当执行INSERT/UPDATE/DELETE的时候,其他事务不呢个读取该数据,因此也称为写入锁定;
1
select * from user where id = 1 for update;
意向共享锁(IS)和意向排他锁(IX):获取共享锁或排他锁之前事务必须先获取意向共享锁(IS)或意向排他锁(IX)。[意向锁是InnoDB数据库操作之前自动加的,不需要用户干预]
自增锁:针对自增列自增长的一个特殊的表级别锁
1
SHOW VARIABLES LIKE 'innodb_autoinc_lock_mode';
锁的粒度:锁定对象的大小是锁的粒度
- 记录
- 表
- 数据库
死锁
多个事务持有锁并相互循环等待其他事物的锁导致所有的事务都无法继续执行
其他实现并发控制的策略
- 基于时间戳的并发控制
- 基于有效性检查的并发控制
- 基于快照隔离的并发控制
故障恢复
- 撤销事务undo:将事务更新的所有数据项恢复为日志中的旧值。
- 重做事务redo:将事务更新的所有数据项恢复为日志中的新值。
- 事务正常回滚/因事务故障中止将进行redo
- 系统从崩溃中恢复时将先进行redo再进行undo