《丁奇-MySQL45讲-07/08》之归纳总结

07 | 行锁功过:怎么减少行锁对性能的影响

  • 二阶段锁协议:在执行某条SQL时加锁,在事务提交后统一释放锁。

  • 设置锁等待的超时时间:innodb_lock_wait_timeout,默认情况下是50秒。

  • 发起死锁检测,innodb_deadlock_detect设置为on,默认情况下是on,缺点就是会耗费大量的CPU资源(发现死锁后主动回滚某一个事务,让其他事务得以继续执行)。

  • 如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁的申请时机尽量往后放。

  • 控制并发量不但可以减少死锁的概率,也可以减少死锁检测带来的性能消耗。

08 | 事务到底是隔离的还是不隔离的

之前总结丁琦老师第三篇文章的时候就已经总结了MVCC的概念,所以今天的文章中就不在对其进行重复总结,不过还是会说下丁奇老师对于MVCC的更为人性的总结。

  • 很重要的一点,begin/start transaction命令并不是一个事务的起点,在执行到它们之后的第一个操作InnoDB表的语句后事务才正式开始,比如说select * from t。如果想要马上开启一个事务,可以使用start transaction with consistent snapshot命令。

  • 简化下MVCC的分析过程:

  1. 版本未提交,不可见;

  2. 版本已提交,但是是在视图创建后提交的的,不可见;

  3. 版本已提交,但是是在视图创建前提交的,可见;

  • 更新数据时读到的数据是当前读,所谓的当前读指的是数据的最新值,而快照读指的是数据的历史版本。

  • select语句如果加锁的话也是当前读,如select * from t where id = 1 lock in share mode或select * from t where id = 1 for update,前一种方式加的是共享锁(S),后一种加的是排它锁(X)。

  • 图片直接摘抄丁奇老师的,我们都知道事务C没提交的情况下会阻塞事务B的更新,但我更好奇的是事务A的查询语句会阻塞吗?一开始我认为是会,因为事务C`加的是排它锁,所以读也是会被阻塞的,但像事务A的查询语句并不会请求锁,所以我还是忍不住尝试了下,结果居然是不会阻塞(MySQL5.7),可能是因为查询语句要获取的是快照读,所以不会发生锁冲突...还是挺难说服自己的。

例子1

  • start transaction with consistent snapshot命令对于在RC隔离级别下的作用相当于start transaction,因为RC级别下每遇到一条语句就会生成新的ReadView。

  • 思考题:要把所有"字段c和id值相等的行"的c值清零。

例子2

具体的流程说明:事务A先创建视图,随后事务B修改了k的值并提交,接着事务A执行更新语句,发现没有符合where条件的语句(被事务B抢先更新了),所以事务A的更新语句就失败了(记录上的事务ID没有发生改变),虽然事务B已经提交,但是是在事务A创建视图后提交的,是不可见的,所以事务A在查询的时候看到的仍然是原来的值,就出现了"明明值没有发生变化可我就是更新不了"的现象,这种场景就是所谓的乐观锁,通常情况下可以判断事务A是否执行失败了,如果失败了就重新发起一个事务,这样子就可以看到新值。

例子3

posted @ 2021-03-23 19:51  zliawk  阅读(137)  评论(0)    收藏  举报