ACID:数据库正确执行的四个基本要素的缩写
原子性(Atomicity)
一致性(Consistency)
隔离性(Isolation)
持久性(Durability)
事务的几种方式
单线程、排他锁(对同一单元的访问进行控制)、读写锁(读读场景时使用)、MVCC(Copy on Write,可以做到所有读是并行,写是串行的效果;也是最优的方案)
什么时候事务需要用到多线程?
内存:很快的动态开辟和消毁一块空间,IOPS很高
磁盘:IOPS低,将大量读写攒成一个batch去执行效率最高
内存的IOPS是磁盘的1000-10000倍(读算写)
在慢速设备(磁盘、网络)的场景下多线程和异步应用的很多;
事务调优:
减少锁的覆盖范围
Myisam表锁->Innodb行锁
原位锁-MVCC多版本锁(重复读和读已提交)
增加锁上可并行的线程数
读写锁分离、允许并行读取数据
选择正确锁类型
悲观锁 发现已有锁,则切换(需要CPU开锁,内存页数据清掉,寄存器清掉)出去等待通知再进行争抢锁;适合并发争抢比较严重场景,假定会冲突时;
乐观锁(自选锁) 发现已有锁,不进行切换出去,自旋主动轮询如发现已不被持有,则锁定;适合并发争抢不太严重的场景
悲观和乐观的区别:悲观认为每次锁定的时间都比较大(wait和notifyAll的悲观场景,典型的悲观场景);乐观认为每次锁定的时间都不长,大部分乐观请求时都会成功,竞争并不激烈,假定不会冲突时。
事务单元之间的Happen-before关系
读写
写读
读读
写写
问题
如何能够以最快的速度完成?
又能保证上面四种操作的逻辑顺序
事务-排队法
排队
序列化读写
优势
不需要冲突控制
劣势
慢速设备
事务-排他锁
针对同一个单元的访问进行访问控制(排他锁)
对可能发生冲突的事务进行排他锁控制(同一队列)
不会发生冲突的事务互不影响同时进行(多队列)
事务-读写锁
针对读读场景可以优化
对读读的场景完全可以进行并行操作;
对读写、写读、写写场景下的操作进行串行(同一队列,序列化)
事务-MVCC
本质就是copy on write
能够做到写不阻塞读(在写的时候可以做到读,阻塞只出现在写写的操作)
多个事务,谁先谁后?
MVCC把每次的写入,放到一个log里,读版本号为5的数据,先找版号为10的数据后,再向前找到版本号为5的数据,
在不同的数据库里都在维护着一个数据的自增号(逻辑时间戳),每次写的时候都加1,如果在一个事务里有写读的话,写时也会自增。
时间戳分为:1.逻辑时间戳(只保证先后顺序);2.物理时间戳(时间的顺序)
如何故障恢复?
可能的错误情况
业务属性不匹配,需要进行数据恢复(原子性)
向smith转账100时,Bob账户不够100,需要进行回滚;记录下来事务之前操作的所有反向操作,在业务单元有问题的时候进行回滚;
系统崩溃(DOWN机)
对于进行了一半的事务,也是需要进行事务回滚的;对应数据库会进入recovery模式
碰到死锁了怎么办?
死锁产生原因
两个线程+不同方向+相同资源=死锁
死锁的解决方案
1.尽可能不死锁(降低隔离级别,不加读锁)
2.碰撞检测(效率高)
3.等锁超时
*主流数据库的做法都是采用碰撞检测辅以等锁超时;
隔离性
以性能为理由,对强一致性的破坏
序列化
-排它锁
可重复读(REPEATABLE READ)
*读写锁,读锁不能被写锁升级
读读可并行
幻象读(可重复读repeatable-read):A事务第一次读取时未有数据条数据的增减,第二次读取时已不是原来的数据条数,而是由B事务对数据的条数据有了增减(避免幻象读,则往往需要添加表级锁,其中Oracle使用多版本数据的方式实现)。
读已提交(READ COMMITTED) 同一事务里的两次读,可能会读到不同版本的数据;不可重复读
*读写锁,读锁可被写锁升级
读读并行
读写并行(写读不可并行)
(不可重复读)A事务中第一次读取更被修改过的数据a,第二次读取新的B事务已经提交的更改数据a(避免不可重复读,只需要对操作的数据添加行级锁即可)。
读未提交(READ UNCOMMITTED) 可能会读到写过程中未提交的数据
*只加写锁,读不加锁
读读并行
读写并行
写读并行
(脏读)A事务读取B事务尚未提交的更改数据(脏读),并在此更改后的数据上进行操作,此时B事务回滚,那么A事务读到的数据根本是错误的。
快照隔离性(向四种场景映射)
针对读多写少场景优化
并行度能达到或超过读未提交,而隔离级别很高
MVCC 快照读 核心思想是无锁编程(Copy on write)
写和写,有没有可能并行呢?
持久性
事务完成以后,该事务对数据库所作的更改便持久的保存在数据库之中
But
如何才能保证数据不丢呢?
RAID保证持久性,RAID Controller保证两块磁盘的一致性-又是一个事务的概念(磁盘的方案)
group commit组提交,如5次提交再落到磁盘上;
IOPS和吞吐量是有翘翘板效应的
事务的调优原则
减少锁的覆盖范围
Myisam表锁->Innodb行锁
原位锁->MVCC多版本(也是一个减少锁的覆盖范围问题)
增加锁上可并行的线程数
读锁写锁分离、允许并行读取数据
选择正确锁类型
悲观锁 适合并发争抢比较严重的场景
乐观锁 适合并发争抢不太严重的场景