MySQL是如何处理并发的?

1、MySQL采用MVCC方式处理读并发,采用LBCC处理写并发,为什么要用这种方式呢?

  1. 只要涉及到并发,那么一定离不开锁。咱们在了解MVCC之前,先看看MySQL有哪些锁。锁的知识大家看看这位大牛的总结吧(偷个懒)

  2. 知道了有哪些锁,那么我们就使用InnoDB引擎,看看并发场景下MySQL是怎么使用锁的。(book表主键索引为bookid)
    图1-1

  3. 事务A未提交,由于是update操作,而且bookid是主键,所以会给 bookid=16 这行记录(聚簇索引)上加X锁。奇怪的事情发生了,事务B竟然可以读到 bookid=16 这行记录,不是加了X锁吗?怎么没有被阻塞呢?

  4. 要解答上面的问题,MVCC就要闪亮登场了。先给大家介绍一下,MVCC的几个重要组成元素: undo log、read view、数据表的三个隐式字段(db_trx_id、roll_pointer、del_flag);

  5. 不着急,我们一个一个来,我们新插入一条数据瞧瞧数据表的隐式字段

-- 首次在数据库插入这条记录,在数据库中会以下表形式保存,有3个隐式字段
-- 事务1
begin;
insert into t_user values(1,'王小虎',20);
commit;
--事务2处理逻辑与id=1这条记录无关
--事务3
begin;
update t_user set name='王小' where id=1;
commit;
步骤idnameagedb_trx_id(最近修改的事务id)roll_pointer(回滚指针)del_flag(删除标记)
11王小虎201nullnull
------
21王小2030x198452(是上一步操作-步骤1中这条记录在undo log的地址值)null
  1. 然后再来说说read view
1、快照读-触发时机:
	select

2、当前读-触发时机:
	select ... for updateselect ... lock in share modeinsertdeleteupdate

3read view就是快照读的时候产生的读视图,它包含下面3个元素:
	trx_list:就是select执行的瞬间,对数据库中当前还未提交的事务做了一个快照,它保存的是此刻所有还未提交事务id的集合;
	low_limit_id:下一次产生read view时的事务id;
	up_limit_id:trx_list中,事务id的最小值;
  1. undo log是回退日志。
  2. 知道了上面这些知识,我们现在就开始正式说说这三者是如何协同实现的MVCC(多版本并发控制)
  3. 先在数据库插入一条记录
-- t_user(id,name,age),其中id是主键
insert into t_user values(1,'王小虎',20);

然后分别开启3个事务

步骤事务5事务6事务7
开启事务开启事务-
update t_user set name=‘王小’ where id=1;select * from t_user where id<10;开启事务
--insert into t_user values(2,‘秋红叶’,25);
提交事务-提交事务
-select * from t_user where id<10;-
一、MVCC流程(只分析事务6,隔离级别为RR):
	1、 步骤二触发快照读,开启read view,此时read view 中各参数为 trx_list={56,7},low_limit_id=8;up_limit_id=52、然后根据如下逻辑进行判断:id=1这条记录最近是被事务3处理过,所以db_trx_id=3
    // 数据库保存的事务早于当前活跃的事务,当前事务能直接访问此记录
    if (db_trx_id < up_limit_id) {
		return true;	
	} 
	// 当前活跃的事务还未提交,但是外面有事务已经提交并保存到了数据库,当前活跃的事务无法访问这条记录
	if (db_trx_id >= low_limit_id) {
		// 去undo log日志链重新递归查询
		return false;
	}
	// 开启read view时,当时活跃的事务之间是不能相互访问的
	if (trx_list.contains(db_trx_id)) {
		// 去undo log日志链重新递归查询
		return false;
	} else {
		return true;
	}

	3、由上述逻辑可知,db_trx_id(3< up_limit_id(5),所以事务6的步骤二能查询到记录。
	4、事务6到步骤五时,read view与步骤二一样,所以它无论如何都不会读到事务7的记录,不会发生幻读。
	5、如果是RC级别,此时的read view元素内容为:
		trx_list={6},up_limit_id=6,low_limit_id=8;
		我们分析一下此时它的查询逻辑:
		db_trx_id(7> up_limit_id(6)
		→ db_trx_id(7< low_limit_id(8)
		→ trx_list{6}不包含db_trx_id(8),
		所以能访问到id=2这条记录,从而发生了幻读!
    
二、理解当前读与快照读
	1、快照读,相当于抓拍,你加不加锁与我无关,提高了读写并发
	2、当前读是LBCC,基于锁的并发控制

2、LBCC大家移步看这位大神的介绍吧

MySQL加锁分析LBCC@ yzyz

3、事务的4大特性

  1. Atomicity 原子性
  2. Consistency 一致性
  3. Isolation 隔离性
  4. Durability 持久性

4、事务的4种隔离级别

  1. Read Uncommitted 读未提交
  2. Read Committed 读已提交
  3. Repeatable Read 可重复读(InnoDB存储引擎默认的级别)
  4. Serializable 串行化

5、不同事务级别带来的并发问题

  1. 脏读:事务A读到了事务B还没提交的记录;
  2. 不可重复读(update时会出现):事务A读取 id=1 的记录时,事务B修改并提交该条记录后,事务A再次读取,会与第一次的结果不一致;
  3. 普通幻读(insert、delete时会出现):事务A读取 id between 1 and 10 的 10 条记录时,事务B删除一条 id=6 的记录并提交后,事务A再次读取,只能读取到 9 条记录;
  4. 特殊幻读:事务A读取 id between 1 and 10 的 9 条记录时(数据库当前只有1-5,7-10这9条数据),事务B插入一条 id=6 的记录并提交后,事务A也插入一条 id=6 的记录,会报错主键冲突;
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值