diff --git a/executor/builder.go b/executor/builder.go index 53e1f7e16df57..b1d27fc873778 100644 --- a/executor/builder.go +++ b/executor/builder.go @@ -2216,7 +2216,10 @@ func (b *executorBuilder) updateForUpdateTSIfNeeded(selectPlan plannercore.Physi if !txnCtx.IsPessimistic { return nil } - if _, ok := selectPlan.(*plannercore.PointGetPlan); ok { + + // The `forUpdateTS` should be refreshed for RC, or the `pointGetExecutor` may not read + // the latest data and no pessimistic locks would be acquired, thus the result is unexpected. + if _, ok := selectPlan.(*plannercore.PointGetPlan); ok && !b.ctx.GetSessionVars().IsPessimisticReadConsistency() { return nil } // Activate the invalid txn, use the txn startTS as newForUpdateTS diff --git a/tests/realtikvtest/pessimistictest/pessimistic_test.go b/tests/realtikvtest/pessimistictest/pessimistic_test.go index fdadded9613c7..2f1fe3478643e 100644 --- a/tests/realtikvtest/pessimistictest/pessimistic_test.go +++ b/tests/realtikvtest/pessimistictest/pessimistic_test.go @@ -3199,3 +3199,40 @@ func TestPessimisticLockOnPartition(t *testing.T) { require.Equal(t, int32(0), <-ch) <-ch // wait for goroutine to quit. } + +func TestRCUpdateWithPointGet(t *testing.T) { + store, clean := realtikvtest.CreateMockStoreAndSetup(t) + defer clean() + + tk := testkit.NewTestKit(t, store) + tk.MustExec("drop database if exists test") + tk.MustExec("create database test") + tk.MustExec("use test") + tk.MustExec("set global tidb_txn_mode = 'pessimistic'") + tk.MustExec("set global tx_isolation = 'READ-COMMITTED'") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (a int key, b int)") + + // Try to cover https://github.com/pingcap/tidb/issues/41581. + tk1 := testkit.NewTestKit(t, store) + tk2 := testkit.NewTestKit(t, store) + tk2.MustExec("use test") + tk1.MustExec("use test") + tk1.MustExec("begin pessimistic") + tk2.MustExec("insert into t values(5, 5)") + tk1.MustExec("update t set b = 22 where a = 5;") + require.Equal(t, uint64(1), tk1.Session().AffectedRows()) + tk1.MustExec("commit") + tk2.MustQuery("select count(1) from t").Check(testkit.Rows("1")) + + tk1.MustExec("begin pessimistic") + tk2.MustExec("insert into t values(6, 6)") + tk1.MustQuery("(select * from t where a = 6 for update) union all (select * from t where a = 7 for update)").Check(testkit.Rows("6 6")) + tk1.MustExec("commit") + + tk1.MustExec("begin pessimistic") + tk2.MustExec("insert into t values(7, 7)") + tk1.MustExec("delete from t where a = 7;") + require.Equal(t, uint64(1), tk1.Session().AffectedRows()) + tk1.MustExec("commit") +}