平凯数据库事务内修改隔离级别

开启全局系统变量 pkdb_eal 后,你可以在已经开始的悲观事务中执行 SET TRANSACTION ISOLATION LEVEL ...,在不结束当前事务的前提下,在 REPEATABLE READREAD COMMITTED 之间切换当前事务的隔离级别。

这个能力适用于需要在同一个事务里临时调整读取可见性的场景。例如:

  • REPEATABLE READ 切换到 READ COMMITTED 后,后续读取可以看到其他事务新提交的数据。
  • READ COMMITTED 切换回 REPEATABLE READ 后,后续读取会回到当前事务开始时的快照。
  • 事务即使已经读取过数据,后续仍然可以继续切换。

使用前提与开启方式

使用该能力前,需要满足以下条件:

  • 当前事务已经开始。
  • 当前事务是悲观事务。建议直接使用 BEGIN PESSIMISTIC
  • 全局系统变量 pkdb_eal 已开启。

开启方式如下:

SHOW GLOBAL VARIABLES LIKE 'pkdb_eal'; SET GLOBAL pkdb_eal = ON;

事务内支持的切换语法如下:

SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

SQL 示例

示例 1:在当前事务中从 REPEATABLE READ 切换到 READ COMMITTED

先准备测试表:

DROP TABLE IF EXISTS demo_change_isolation_accounts; CREATE TABLE demo_change_isolation_accounts ( id INT PRIMARY KEY, balance INT ); INSERT INTO demo_change_isolation_accounts VALUES (1, 1000);

会话 1:

SET GLOBAL pkdb_eal = ON; SET SESSION transaction_isolation = 'REPEATABLE-READ'; BEGIN PESSIMISTIC; SELECT balance FROM demo_change_isolation_accounts WHERE id = 1; -- 1000

会话 2:

BEGIN PESSIMISTIC; UPDATE demo_change_isolation_accounts SET balance = 1200 WHERE id = 1; COMMIT;

会话 1:

SELECT balance FROM demo_change_isolation_accounts WHERE id = 1; -- 1000 SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT balance FROM demo_change_isolation_accounts WHERE id = 1; -- 1200 COMMIT; DROP TABLE demo_change_isolation_accounts;

示例 2:在当前事务中从 READ COMMITTED 切换到 REPEATABLE READ

先准备测试表:

DROP TABLE IF EXISTS demo_change_isolation_accounts; CREATE TABLE demo_change_isolation_accounts ( id INT PRIMARY KEY, balance INT ); INSERT INTO demo_change_isolation_accounts VALUES (1, 1000);

会话 1:

SET GLOBAL pkdb_eal = ON; SET SESSION transaction_isolation = 'READ-COMMITTED'; BEGIN PESSIMISTIC; SELECT balance FROM demo_change_isolation_accounts WHERE id = 1; -- 1000

会话 2:

BEGIN PESSIMISTIC; UPDATE demo_change_isolation_accounts SET balance = 800 WHERE id = 1; COMMIT;

会话 1:

SELECT balance FROM demo_change_isolation_accounts WHERE id = 1; -- 800 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; SELECT balance FROM demo_change_isolation_accounts WHERE id = 1; -- 1000 COMMIT; DROP TABLE demo_change_isolation_accounts;

注意事项与限制

  • 已开始的悲观事务,且 pkdb_eal = ON 支持在当前事务内把隔离级别从 REPEATABLE READ 切到 READ COMMITTED,也支持反向切换。
  • 事务已经读过数据后再切换: 仍然生效,后续读取按切换后的隔离级别表现。
  • 已开始的悲观事务,但 pkdb_eal = OFF 语句会报错:ERROR 1568 (25001)
  • 乐观事务: 语句不会改变当前事务的读取行为。
  • START TRANSACTION READ ONLY AS OF TIMESTAMP ... 语句不会改变当前 stale read 事务的快照。
  • 事务外执行: 这不是本文功能的使用方式;它不会改写 transaction_isolation。如果你的目标是修改后续事务的默认隔离级别,请使用 SET SESSION transaction_isolation = ...
  • SELECT ... FOR UPDATE 切换后仍然保持悲观锁语义。
  • SAVEPOINT 切换后仍然可以继续使用 ROLLBACK TO SAVEPOINT

相关文档