并发控制
并发控制保证数据一致性的方法:
(1)锁:
普通锁:串行执行
读写锁:读读并发
(2)数据多版本: 读写并发
(1)写任务发生时,将数据克隆一份,以版本号区别 ;
(2)写任务操作新克隆的数据,直至提交
(3)并发读任务可以继续读旧版本的数据,不至于阻塞
实现读取旧版本数据:
redo日志:redo日志用于保障已提交数据的ACID特性。
如果每次都将事务提交的数据更新随机写到磁盘上,性能较低。优化:将修改数据顺序写到redo日志里,定期刷到磁盘上。
undo日志:undo日志保障,未提交数据对数据库ACID特性产生影响。
事务未提交前,将修改数据的镜像(修改前的旧版本),当事务回滚或者数据库崩溃时,恢复旧版本。
insert行为undo日志存PK,update/delete行为undo日志存row。分别存在不同的buffer里。
回滚段:存储undo日志
InnorDB做到高并发:InnorDB是基于多版本并发控制(MVCC)的存储引擎
回滚段里的数据是历史数据的快照,快照读(不加锁一致性读)是innorDB如此高并发的原因。
普通的select都是快照读,除非显示加锁,如select .. fro update 。
快照读读取到的数据版本与什么有关?
RC下,快照读总是读取到最新的行数据快照(已提交的事务)
RR下,读取首次read的数据版本,与并发事务的开始时间、互斥关系(不加锁)无关。假设首次read的时间记为T,不会读取T时间后提交的记录。
锁
资料:https://mp.weixin.qq.com/s/tmkRAmc1M_Y23ynduBeP3Q
1.七种锁
1) 自增锁:
是特殊的表级别锁,针对事务插入AUTO_INCREMENT列。如果一个事务在插入,其他事务必须等待。
2)共享/排它锁
共享锁S:读锁
排它锁X:写锁。很强的锁,不与其它锁兼容。
读读可以并行,读写、写写互斥。
3)意向锁
意向锁是在事务要加共享/排它锁之前先做的一个意向声明。是一个表级别的锁。
意向共享锁IS:事务有意向向表中某些行加共享s锁
意向排它锁IS:事务有意向向表中某些行加排它x锁
4)插入意向锁
专门针对insert操作。多个事务,在同一个索引,同一个范围,如果插入位置不冲突,不会阻塞彼此。
5)记录锁
封锁索引记录。比如:select ... for update
6)间隙锁
封锁索引记录的间隔。防止其他事务在间隔中插入数据。比如:select .. betweend ... and .. for update
7) 临键锁
封锁索引记录和索引区间。防止幻读。
乐观锁和悲观锁。乐观锁使用版本号,悲观锁是一直等待;
表锁:
lock table
行锁:
begin 开启事务
sql
commit 提交事务
2.事务
1)四个特性:
A原子性:事务里所有操作要么全部都执行,要么全不执行
C一致性:所有操作全部成功或全部失败
I隔离性:事务中间处理过程对外不可见
D永久性:数据修改是永久的
2)并发事务带来的问题:
更新丢失:乐观锁使用版本号,低版本的更新会丢弃
脏读:事务A读到了事务B修改但未提交的内容
不可重复读:事务A读到事务B修改已提交的内容。举例:事务A第一次来查询,做了后续的业务处理,事务B进行数据修改的提交,事务A再次来查询,此时数据的修改可能会影响事务A的业务逻辑判断。
幻读:事务A读到了事务B提交的更新数据。举例:事务A第一次查询只有三条数据需要修改,事务B进行新增数据的提交,最终更新了四条数据。
3)事务隔离级别:mysql默认的隔离级别是Repeated Read(RR)可重复读
查看事务隔离级别:show variables like 'tx_isolation'
隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交 | 是 | 是 | 是 |
读已提交 | 否 | 是 | 是 |
可重复读 | 否 | 否 | 是 |
可串行化 | 否 | 否 | 否 |
可重复读的mvcc机制:
select操作不会更新版本号,是快照读(历史版本)
insert、update、delete 会更新版本号,可查询到其他事务提交的修改(即会出现幻读)
4)优化建议:
1.尽可能让所有数据检索通过索引完成,避免无索引行锁升级为表锁
2.尽可能检索条件避免间隙锁
3.尽可能控制事务大小,减少锁定资源量和时间长度
4.尽可能低级别事务隔离
3.各种sql加了什么锁
https://mp.weixin.qq.com/s/wGOxro3uShp2q5w97azx5A