ylldty
(Ti D Ber Q Yky5 Dvm)
1
TIDB 的乐观事务默认是 SI 级别,对于 Select 语句,如果读取的 rowid 有 lock 记录,那么需要等锁、清锁、重试
TIDB 的悲观事务在 RC 提交读隔离级别中,对于 Select 语句是快照读,即使 rowid 有 lock 记录,也不需要等锁,直接读取 write 记录最新提交的 value 即可
但是悲观事务默认隔离的 RR 可重复读级别,对于 Select 语句快照读,是和快照读一样不需要检测 lock 记录呢,还是和 si 一样,需要 tikv 提前检测lock记录,从而需要等锁呢?
dba远航
(Ti D Ber M Lo7 Bqhk)
3
快照读只要是确认是提交过的就行,不需要考虑锁的问题
TiDB 实现了快照隔离 (Snapshot Isolation, SI) 级别的一致性。为与 MySQL 保持一致,又称其为“可重复读” (REPEATABLE READ)。
与 MySQL 可重复读隔离级别的区别
MySQL 可重复读隔离级别在更新时并不检验当前版本是否可见,也就是说,即使该行在事务启动后被更新过,同样可以继续更新。这种情况在 TiDB 使用乐观事务时会导致事务回滚,导致事务最终失败,而 TiDB 默认的悲观事务和 MySQL 是可以更新成功的。
1 个赞
这里的锁是不一样的,乐观锁和悲观锁中的读写冲突指的是,两阶段提交的时候,Prewrite 加的锁会阻塞能看到该锁的事务的读,原因是写下该 lock 的事务可能已经获取了 commit ts,且 commit ts 小于看到锁的事务的 start ts,这时候 select 都要等锁。
你描述的悲观锁不用等锁,指的是悲观锁两阶段提交前,会加一把锁,确保两阶段提交的时候不会发生 write conflict 的错误,这里的事务一定还没获取 commit ts,所以悲观锁不会阻塞读(和乐观锁一样,悲观事务提交仍要走一遍完整的 Percolator 提交流程,只有当所有悲观锁被 Prewrite 成 Percolator 的锁才会到 Commit 阶段)。
1 个赞
ylldty
(Ti D Ber Q Yky5 Dvm)
6
通过 DEBUG tikv 的代码:
![image](https://asktug.com/uploads/default/original/4X/d/7/d/d7d8fcd495f18c93b75bab04d089102b37081cdf.jpeg)
可以总结有两种场景:
-
如果只有悲观事务,那么 RC/RR 级别的 select 快照读会忽略其他悲观事务加的锁。例如有两个悲观事务,一个事务t1 执行 select for update,不提交,另一个事务 t2 执行 select 快照读。虽然 t2 快照读发送给 tikv 的请求仍然是 si 级别的,也检测到了 t1 事务所加的悲观锁,但是会主动忽略这个锁,而直接返回上一个 commit 记录,无需等锁或者重试
-
如果悲观事务和乐观事务共存,RC/RR 级别的 select 快照读可能会遭遇等锁、重试。例如两个事务,一个事务是乐观事务 t1,当前正在进行二阶段提交,目前刚刚 prewrite 完成,还未能 commit。事务 t2 是悲观事务,执行 rc 级别的快照读,此时快照读拿到时间戳 read_ts2。这个时候 t2 的快照读会检测到 t1 的 lock 乐观锁。如果无法确定这个乐观锁最后提交的时间 commit_ts1 到底会大于 read_ts2 还是小于 read_ts2,因此需要等锁、重试。防止事务 t2 快照读成功后,突然又有乐观事务把事务提交到了 read_ts2 之前,正确性得到了提升。
第二种情况同样适用于悲观事务进行二阶段提交时,prewrite 完成后,因为此时悲观事务的悲观锁被修改为乐观锁。
1 个赞
ylldty
(Ti D Ber Q Yky5 Dvm)
7
Trouble
(Ti D Ber Qf Zc40ep)
8
快照出现的目的就是为了消除部分锁,使得读写可以同时进行
1 个赞
system
(system)
关闭
9
此话题已在最后回复的 60 天后被自动关闭。不再允许新回复。