TIDB 悲观锁加锁流程

版本v4.0.15
1、当TIDB 使用悲观锁的模式,锁信息 是在prewrite 阶段 的时候写入tikv的嘛?如果这个事务异常中断没有提交,那么tikv锁信息需要清理,它的流程是怎么样?
2、关于max-txn-ttl 参数的问题(当TIDB 使用悲观锁的模式),官网是说
单个事务持锁的最长时间,超过该时间,该事务的锁可能会被其他事务清除,导致该事务无法成功提交。
举个例子:
比如一个A事务更改5行数据,max-txn-ttl 设置了1秒,是不是说 在A事务对这5行数据加了锁之后,如果不提交释放锁,1秒之后,如果有B事务也修改这5行数据,那么A事务持有的这5行数据的锁就被清理掉了
这么理解对吗?

1 个赞

1、悲观模式是在DML阶段写入悲观锁到tikv, 在完成数据操作后开始写入,比如update 10万行,是在10万数据都写到tidb后开始的。DML阶段写入的悲观锁和prewrite时略有不同,缺少一些具体信息。在prewrite时会按原有的流程再重新写一遍锁信息。
在读写时遇到锁会等待,超过ttl时间后可能会进行清理,另外GC时也会进行锁清理


2、超出max-txn-ttl 事务会被回滚,另外也会计算一个lockttl


2 个赞

悲观锁是在prewrite之前就写了占位锁
事务中断清理时,是由另外一个事务来操作,根据主锁提交状态,提交就前滚,未提交就回滚,prewrite之前的占位锁状态当然属于回滚。
超过max-txn-ttl,锁状态可能被其他事务清理掉,这应该是防止过长事务导致的问题。

1 个赞

请问老师,悲观锁信息写入到tikv的时候 应该是在prewrite 的时候才写入吧,prewrite之前的占位锁只是保留在内存中吧,如果prewrite 发生了,锁信息也写入到了tikv,这个时候事务异常中断没有正常提交或者回滚,那么这个事务留下的锁信息是一个什么样的清理机制呢?

1 个赞

我不是已经回答得很明确么,悲观锁模式是在prewrite之前写占位锁的,乐观锁才是prewrite阶段写锁。
清理流程是等后面事务写到相关行时,检查之前残留的锁情况,只有主锁已经提交的事务进行前滚,其他情况都是回滚。

1 个赞

暂时懂了,谢谢老师

1 个赞

请问老师,无论是悲观事务还是乐观事务提交的时候,是不是只要完成第一阶段的prewrite 之后,这时即使还没来的及完成第二阶段的commit ,即使这个事务异常终止,以后也可以靠锁信息来完成自动提交,就像是mysql的二阶段提交,只要写入binlog了,即使mysql宕机,以后也可以靠这个事务的binlog完成自动提交

只有异步提交才是prewrite完成后才是完成提交状态,条件是行数不超256,总大小不超4K。其他的都得等着commit pimary lock key后才是完成提交,对于未提交完成的key会resolve lock,进行回滚

老师,您好,不是很懂,是否异步提交跟事务涉及的行数和事务的大小有关系?异步提交是v5.0才有的功能吧?在v5.0之前,事务是两阶段提交,我个人理解事务 事实上的提交成功应该要在第二阶段的commit 阶段,把主锁信息给清理了,这个事务才算是事实的提交成功了,
如果仅在第一阶段prewrite ,仅仅把主锁信息给写入到tikv,这个事务就异常中断了,那么这个事务就应该就回滚,所对应的主锁信息就应该被清理
不知道这样理解对不对

假设在悲观锁模式下
请问老师,如果一个事务A执行DML之后,不提交事务,A事务把占位锁信息写到了tikv中,如果这个A事务还未提交,如果有B事务来执行修改A事务锁住的行,这个B事务肯定会被阻塞,那么这个B事务获取锁的一个整体逻辑大概是怎么样的呢?B事务是会去TIKV里面找这个A事务写入的占位锁信息,然后进行判断的嘛?

如果A事务异常终止,A事务写到tikv里面的占位锁信息肯定没有被清理,那么之后来了个C事务修改A事务之前锁住的行是可以被修改的(我自己测试过),C事务又怎么可以修改之前A事务锁住的行? 这又是一个怎么样的加锁判断规则呢?

B事务是会去TIKV里面找这个A事务写入的占位锁信息,然后进行判断的嘛?-----------是的。
如果A事务还在会阻塞,如果A事务不在C事务会通过主锁状态判断是该前滚还是回滚。

老师,周末好
我描述的场景是A事务还未进行commit,按照我的理解,这时A事务只会写入占位锁(其实不是很懂占位锁的实现原理),这个时候主锁还是没有写入的,其它事务怎么通过占位锁去判断A事务是正常存在还未提交还是A事务异常中断了?请老师指点

占位锁也是有主锁与指向锁,所以按主锁未提交类型处理,回滚

请问老师,是可以通过占位锁是可以去判断事务是正常未提交的状态还是事务异常中断的状态吧?有些文章说是 占位锁只是一个空锁,占位锁的原理是什么?

你可以这样理解,占位锁与正常锁的区别只在于正常锁里面的写入到default列簇的版本信息,因为这时候还没有写入default,所以这里信息没有而已。所以按正常的主锁指向锁来理解占位锁就行。