问题描述
在可重复读的隔离级别下,业务执行过程中会报如下错误。
ERROR 6235 (25000): can't serialize access for this transaction
问题原因
可重复读隔离级别无法防止幻读现象,因为 UPDATE 语句总是需要读取数据最新的版本,当可重复读隔离级别的事务中执行 UPDATE 操作读取到其他事务提交的数据修改时,就产生了幻读。 OceanBase 数据库的隔离级别实现与 Oracle 数据库类似,无论是可重复读(Repeatable Read)还是可串行化(Serializable),底层逻辑均为可串行化。无论是可重复读还是可串行化,只要发生幻读,就会报无法串行化的错误。 问题复现示例。
会话窗口 SESSION01 操作:
使用 MySQL 模式库。
obclient [(none)]> use db_mysql Database changed设置事务的隔离级别。
obclient [db_mysql]> set transaction_isolation='repeatable-read'; Query OK, 0 rows affected (0.001 sec)查询表内容。
obclient [db_mysql]> select * from t1;输出结果如下:
+----+------------+ | id | log_date | +----+------------+ | 1 | 2023-06-30 | | 2 | 2023-06-30 | | 3 | 2023-02-15 | +----+------------+ 3 rows in set (0.036 sec)开启事务。
obclient [db_mysql]> begin; Query OK, 0 rows affected (0.000 sec)事务启动之后查询表内容。
obclient [db_mysql]> select * from t1;输出结果如下:
+----+------------+ | id | log_date | +----+------------+ | 1 | 2023-06-30 | | 2 | 2023-06-30 | | 3 | 2023-02-15 | +----+------------+ 3 rows in set (0.005 sec)
会话窗口 SESSION02 操作:
使用 MySQL 模式库。
obclient [(none)]> use db_mysql Database changed obclient设置事务的隔离级别。
obclient [db_mysql]> set transaction_isolation='repeatable-read'; Query OK, 0 rows affected (0.001 sec)开启事务。
[db_mysql]> begin; Query OK, 0 rows affected (0.000 sec)事务启动之后删除表数据。
obclient [db_mysql]> delete from t1; Query OK, 3 rows affected (0.038 sec)提交删除表数据的事务。
obclient [db_mysql]> commit; Query OK, 0 rows affected (0.023 sec)
在会话窗口 SESSION01 上执行 update 语句的操作:
obclient [db_mysql]> update t1 set log_date=current_date() where id =1;
ERROR 6235 (25000): can't serialize access for this transaction
适用版本
OceanBase 数据库 V2.x 和 V3.x 版本。
解决方法
降低事务隔离级别,改为 READ COMMITTED 即可解决问题。
obclient [db_mysql]> set transaction_isolation='read-committed';
Query OK, 0 rows affected (0.001 sec)