MySQL 事务和锁

事务

事务原理

事务四大特性

事务有四大特性 ACID,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久化(Durability)
* 原子性(Atomicity):简单理解为一个事务中所有的操作是一个整体,要么全部完成,要么全部失败
* 一致性(consistency):应用系统从一个正确的状态到另一个正确的状态.而ACID就是说事务能够通过AID来保证这个C的过程.C是目的,AID都是手段
* 隔离性(Isolation):事务之间不会相互影响,由锁机制和MVCC(多版本并发空值)实现。隔离性分为:读未提交、读已提交、可重复读、串行化
* 持久化(Durability):事务完成后需要写入磁盘,事务提交后,对数据的修改是永久性的

事务级别

* 读未提交:可以看到其他事务未提交的数据,由于是未提交的数据,因此其他事务就会读取到不一致的树,造成脏读
* 读已提交:只能看到其他事务已提交的数据,如果事务中两次查询过程中有其他事务提交修改数据,因此会造成两次查询的结果不一致,因此这个级别会造成不可重复读问题
* 可重复读:事务过程中读取的数据都是一致的,即使其他事务有提交修改数据。如果事务过程中其他事务有插入数据,会造成幻读
* 可串行化:最高的隔离级别,多个并行事务串行化执行,不会产生安全性问题

MVCC(Multiversion Concurrency Control) 多版本并发控制

MVCC的实现是通过保存数据在某一个时间点快照来实现的,一般是执行第一个查询SQL创建快照。之后无论其他事务如何修改数据,本次事务内读取的数据都是一致的

如上图所示,每行数据都会有多个版本的数据,版本ID也就是事务ID,事务ID是事务开始的时候向InnoDB的事务系统申请的,是按申请顺序严格递增的。

锁类型

按照锁范围可以分为:全局锁、表级锁、页级锁、行级锁,按属性可分为: 共享锁和排它锁,按照模式可分为:乐观锁和悲观锁

全局锁

* 对整个数据库实例加锁,命令: flush tables with read lock(FTWRL)
* 使用这个命令其他线程的一下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句
* 使用场景:全库逻辑备份
* 缺点:主库上备份,备份期间不能执行更新、业务基本停摆。从库备份,备份期间从库不能执行主库同步过来的binlog,会导致主从延迟
* 可重复读隔离级别下替换备份解决方案: mysqldump -single-transaction 

表级锁

* 锁整个表,命令: lock tables ... read/write。可以用 unlock tables 主动释放锁
* 除了限制别的进程读写,也会限定本线程接下来的操作。比如:A 线程执行: lock tables t1 read, t2 write 语句,本线程也只能执行读t1,读写t2的操作
* MDL(metadata lock) 访问的时候自动加上,当对表做增删改查操作加 MDL 读锁,对表做结构变更加 MDL 写锁。读锁之间不互斥,读写锁、写锁之间互斥

页级锁

* 页级锁是 MySQL 中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。因此,采取了折衷的页级锁,一次锁定相邻的一组记录
* BDB 引擎支持页级锁

行级锁

* 行级锁是在需要的时候加上,事务结束释放,也就是两阶段锁协议。因此尽可能的把锁冲突影响大的语句放在事务最后执行
* 行级锁不是锁记录,而是锁索引,如果一条SQL语句用不到索引是不会使用行级锁的,会使用把整张表锁住

共享锁

* 又称读锁,简称 S 锁,当事务对数据加上读锁之后,其他事务只能对该数据加读锁,不能做任何修改操作,也不能添加写锁。主要是为了支持并发读取,避免修改数据导致的不可重复读问题
* SQL 语句: select ... lock in share mode 

排它锁

* 又称写锁,简称 X 锁,当事务对数据加上写锁之后,其他事务不能对该数据加读锁,也不能加写锁,排它锁是互斥的
* SQL 语句: select … for update
* 写锁主要是为了解决在修改数据时,不允许其他事务对当前数据进行修改和读取操作,从而可以有效避免”脏读”问题的产生
posted @ 2022-07-05 22:52  itabel  阅读(88)  评论(0编辑  收藏  举报