Inconsistent behavior between READ COMMITTED and REPEATABLE READ: UPDATE blocks under RC but returns duplicate-key error under RR
- Dominant language
- Go
- Stars
- 40.5k
- Forks
- 6.2k
- PR merge metrics
- PR metrics pending
Description
## Bug Report
### 1. Minimal reproduce step (Required)
I tested the following case on TiDB v8.5.6 under both READ COMMITTED and REPEATABLE READ isolation levels.
The key observation is that, under READ COMMITTED, statement `[2-1]` is blocked by Transaction 1 and then continues successfully after Transaction 1 commits. However, under REPEATABLE READ, the same statement `[2-1]` does not wait first, but immediately returns a duplicate-key error. This difference leads to inconsistent final database states under the same input schedule and commit order.
#### Table initialization
```sql
DROP TABLE IF EXISTS t0;
CREATE TABLE t0(c0 BOOL UNSIGNED);
INSERT INTO t0 VALUES ('3');
CREATE INDEX i0 ON t0(c0);
INSERT IGNORE INTO t0(c0) VALUES (-79017214) ON DUPLICATE KEY UPDATE c0=DEFAULT(t0.c0);
INSERT DELAYED INTO t0 VALUES (0.750845995730333);
INSERT IGNORE INTO t0(c0) VALUES (NULL);
CREATE UNIQUE INDEX i1 ON t0(c0 DESC);
```
#### Transaction 1
```sql
[1-0] START TRANSACTION WITH CONSISTENT SNAPSHOT;
[1-1] INSERT IGNORE INTO t0(c0) VALUES (0.40952306524265225) ON DUPLICATE KEY UPDATE c0=t0.c0;
[1-2] DELETE FROM t0;
[1-3] INSERT LOW_PRIORITY INTO t0 VALUES (0.9922956147972667) ON DUPLICATE KEY UPDATE c0='-79017214';
[1-4] COMMIT;
```
#### Transaction 2
```sql
[2-0] START TRANSACTION WITH CONSISTENT SNAPSHOT;
[2-1] UPDATE t0 SET c0=((false)REGEXP(t0.c0));
[2-2] UPDATE t0 SET c0=t0.c0;
[2-3] SELECT t0.c0 FROM t0 FOR UPDATE;
[2-4] INSERT INTO t0 VALUES (1.2232);
[2-5] COMMIT;
```
#### Input schedule (Not actual execution order in dbms)
```text
[1-0, 2-0, 1-1, 2-1, 2-2, 2-3, 2-4, 1-2, 1-3, 1-4, 2-5]
```
In my test, `[2-1]` behaves differently under READ COMMITTED and REPEATABLE READ.
### 2. What did you expect to see? (Required)
I expected the behavior of this case under READ COMMITTED and REPEATABLE READ to be consistent with respect to the lock conflict and execution order.
In particular, since Transaction 1 has already executed `[1-1]` before Transaction 2 executes `[2-1]`, statement `[2-1]` should first encounter the lock/conflict caused by Transaction 1. Therefore, under the same input schedule and commit order, I expected `[2-1]` to either:
1. block under both READ COMMITTED and REPEATABLE READ until Transaction 1 commits, and then continue consistently; or
2. fail consistently under both isolation levels.
I did not expect READ COMMITTED to block first while REPEATABLE READ immediately returns an error before waiting, because this difference changes the subsequent execution and leads to different final database states.
### 3. What did you see instead? (Required)
Under READ COMMITTED, statement `[2-1]` is blocked first. After Transaction 1 commits, `[2-1]` continues successfully. The final table state is:
```sql
SELECT * FROM t0;
```
Result:
```text
+------+
| c0 |
+------+
| 0 |
| 1 |
+------+
```
Under REPEATABLE READ, statement `[2-1]` does not block first. Instead, it directly returns a duplicate-key error:
```sql
mysql> UPDATE t0 SET c0=((false)REGEXP(t0.c0));
ERROR 1062 (23000): Duplicate entry '0' for key 't0.i1'
```
After the remaining statements are executed, the final table state is different:
```sql
SELECT * FROM t0;
```
Result:
```text
+------+
| c0 |
+------+
| 1 |
+------+
```
Therefore, under the same test case and input schedule, READ COMMITTED and REPEATABLE READ produce inconsistent behavior and inconsistent final database states.
Note: In a few cases, when I repeatedly ran this test case under READ COMMITTED, I also observed the same behavior as under REPEATABLE READ, namely that [2-1] returned ERROR 1062.
I find this very strange. Whether [2-1] blocks or returns an error should not be random, and its behavior should not be inconsistent with that under REPEATABLE READ.
### 4. What is your TiDB version? (Required)
```sql
mysql> select version();
+--------------------+
| version() |
+--------------------+
| 8.0.11-TiDB-v8.5.6 |
+--------------------+
```
Contributor guide
Assessment
This issue has not been assessed yet.