关于 TiKV 悲观锁的疑问

在使用 TiKV 的 rust client 时,创建两个悲观事务,并发 put 相同的 key,只会有一个成功,失败的报错信息如下:
PessimisticLock error: MultipleKeyErrors([KeyError(KeyError { locked: None, retryable: “Error(Txn(Error(Mvcc(Error(WriteConflict { start_ts: TimeStamp(461117627059142663), conflict_start_ts: TimeStamp(461117627059142658), conflict_commit_ts: TimeStamp(461117627059142671), key: [116, 0, 0, 0, 37, 95, 114, 1, 110, 97, 109, 101, 49, 0, 0, 0, 252, 1, 169, 12, 128, 0, 0, 0, 0, 0, 250], primary: [116, 0, 0, 0, 37, 95, 114, 1, 110, 97, 109, 101, 49, 0, 0, 0, 252, 1, 169, 12, 128, 0, 0, 0, 0, 0, 250], reason: PessimisticRetry })))))”, abort: “”, conflict: Some(WriteConflict { start_ts: 461117627059142663, conflict_ts: 461117627059142658, key: [116, 0, 0, 0, 37, 95, 114, 1, 110, 97, 109, 101, 49, 0, 0, 0, 252, 1, 169, 12, 128, 0, 0, 0, 0, 0, 250], primary: [116, 0, 0, 0, 37, 95, 114, 1, 110, 97, 109, 101, 49, 0, 0, 0, 252, 1, 169, 12, 128, 0, 0, 0, 0, 0, 250], conflict_commit_ts: 461117627059142671, reason: PessimisticRetry }), already_exist: None, deadlock: None, commit_ts_expired: None, txn_not_found: None, commit_ts_too_large: None, assertion_failed: None, primary_mismatch: None })])

但是我记得在 TiDB 中,两个悲观事务对同一个 key 上锁,后上锁的会阻塞住而不是直接失败吧,请问这里为何存在这样的区别呢

报错的时候,第一个事务已经提交了吗?

是的,第一个事务已经提交了,不提交的话是会阻塞吗

是的,如果第一个事务没提交,第二个事务如果跟第一个事务冲突的话会阻塞。当第一个事务提交后,第二个事务会返回报错。

了解了,多谢解答

一个锁,一个堵塞。

还有个问题想请教下,为什么说悲观锁更适合写多的场景呢,悲观锁相比乐观锁在写多的场景下优势在哪里

悲观锁与乐观锁的关键区别在何时检测冲突以及遇到冲突后的行为。
乐观锁是在用户commit后再去检测有没有事务冲突,因此乐观锁的更适合冲突不高的场景,但是真遇到了冲突需要回滚,代价肯定是比悲观锁高的。
悲观锁是直接对需要修改的对象加锁,因此不存在commit之后冲突回滚的问题。如果事务冲突多,悲观锁的效率会比乐观锁高。但悲观锁的劣势就是并发度不如乐观锁。
如何选择乐观锁与冲突锁,应该针对详细的业务场景而设定,并不是说写多就适合悲观锁。