OceanBase 的 Oracle 模式竟然可以使用 Repeatable Read?

2024-08-30 15:28

本文主要是介绍OceanBase 的 Oracle 模式竟然可以使用 Repeatable Read?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

OceanBase 的 Oracle 模式不是只支持 2 种隔离级别:读已提交(Read Committed)和可串行化(Serializable)。

作者:任仲禹,爱可生数据库工程师,擅长故障分析和性能优化。

爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

本文约 1600 字,预计阅读需要 5 分钟。

背景

看到文章标题会有个疑惑,OceanBase 的 Oracle 模式不是只支持 2 种隔离级别:

  • 读已提交(Read Committed)
  • 可串行化(Serializable)

为什么还讨论在 OBoracle 下使用 可重复读(Repeatable Read) 隔离级别这个问题,一切的起因是交付时遇到的客户疑问:

“我的 JAVA 应用通过 oceanbase-jdbc 访问 OBOracle 数据库,业务上想实现 MySQL 可重复读的效果(即事务内 2 次相同查询看到的数据是不变的),所以我将会话设置为只读 conn.setReadOnly(true),但程序运行结果不符合业务预期。”

乍一听没完全理解,沟通后才梳理清楚:

  1. 客户了解到 set transaction read only; 命令可以实现可重复读的效果。
  2. 所以应用中配置了 conn.setReadOnly(true) 想达成此目的。

官网原文:设置 ReadOnly,不推荐执行 set session transaction readonly,推荐使用 Connection.setReadOnly(xx) 接口。

此时,问题剩俩:

  1. OBoracle 中命令 set transaction read only; 为啥能实现可重复读效果?
  2. 配置 conn.setReadOnly(true) 是否正确,不正确该如何配置?

分析

排查涉及的环境:

  • OBoracle 模式 323bp10hotfix5
  • oceanbase-jdbc 2.4.3
为啥 set transaction read only 能实现可重复读效果?

在 OceanBase 中,只读事务中的所有查询都引用了数据库的同一份快照,从而提供多表、多查询、读取一致的视图。所以在只读事务内 2 次相同查询所看到的数据是一致的,也就实现了可重复读的效果。这在对于多用户更新相同表并且运行多个查询时的场景非常有用,也满足客户的业务需求。

配置 conn.setReadOnly 是否正确?

截取了程序运行堆栈,客户环境用的 Hikari 连接池,调用路径从下往上为【Hikari -> OceanBase-client -> setReadOnly -> setSessionReadOnly】。

最终 setSessionReadOnly 调用的是 set session transaction read only 命令。

按过往 DB 经验,“set transaction read only” 等同于 “set session transaction read only”,[session] 只是默认值而已(MySQL 就是这么做的)。*

在 OBOracle 中实验一下:

set transaction read only

set session transaction read only

通过测试可知,两者的语义和效果是不一样的。虽然都能实现其作用范围内只读,但通过和 OceanBase 支持人员了解到,还是有以下区别:

  • 作用范围不同
    • set transaction read only 仅作用于当前事务,一旦该事务结束(Commit 或 Rollback),设置失效,会话中后续事务不会继承该设置。
    • set session transaction read only 则影响整个会话中的所有事务,一旦设置,会话中接下来的所有事务都会被设置为只读模式,直到会话结束或重新设置为可读写模式。
  • 是否可以引用数据库快照
    • SET TRANSACTION 命令开启的只读事务才能引用数据库的快照(继而通过读取一致性视图以获得RR的效果)。
    • SET SEESION TRANSACTION 命令无法使只读事务获得快照。

正确的配置方式

既然 conn.setReadOnlyset session transaction read only)无法实现效果,那如何实现 set transaction read only 命令带来的可重复读的效果呢?

OceanBase 产研提供了一个参数:要达成效果,除了需要设置 conn.setReadOnly(True),还需在 JDBC option 中添加参数:

  • oracleChangeReadOnlyToRepeatableRead=True

该参数在 oceanbase-client 2.4.7 引入,目的是实现可重复读(实质是快照读)的效果。

应用配置完成后,确实有效果。截止本文发布,官网查不到该参数的详细说明,我们先结合源码看下它的实现方式:

对于 setReadOnly,如果满足了 isOracleMode = trueoracleChangeReadOnlyToRepeatableRead = true 情况下,将会把会话的隔离级别设置为 setTransactionIsolation(readOnly ? 4 : 2)

本例场景下, readOnly 的值被设置是 True,那么传递给 setTransactionIsolation 方法的值就是 4 。

由上可知,当值为 4 时,JDBC 将会传递下述 SQL 给后端 OBServer:

  • SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ

前文提到 OBoracle 不是仅支持 RC 和 Serializable 吗,那该命令发到 OB上的行为是怎样的? 继续测试下:

结果是 OBoracle 可以实现可重复读的效果,且通过客户端命令查询到当前会话被设置为了 REPEATABLE READ。

Repeatable Read 和 Serializable

最后再简单说明下,官网提到 OB 的 MySQL 模式支持 3 种隔离级别(RC、RR、Serializable),Oracle 模式支持 2 种(RC、Serializable)。但是实际在 OceanBase 数据库中只实现了 2 种隔离级别,即读已提交(RC)和可串行化(Serializable)。

  • 当用户指定 RR 隔离级别时,实际使用的是 Serializable。也就是说,OceanBase 数据库的 RR 隔离级别更加严格,不会出现幻读的异常情况。
  • 但在底层实现上,OceanBase 数据库的 Serializable 隔离级别实际使用 快照隔离(Snapshot Isolation,SI),不能保证严格的可串行化。

结论

应用通过 oceanbase-client 驱动访问 OceanBase Oracle 模式数据库时,要想实现 Repeatable Read(可重复读) 的效果,除了需要设置 setReadOnly 为 True,还需要满足:

  • oceanbase-client >= 2.3.8 版本
  • JDBC Option 中配置 oracleChangeReadOnlyToRepeatableRead=True

OceanBase Oracle 模式数据库中,会话可以被设置为 RR 隔离级别,但会话变量只是显示为 RR ,实际底层实现上用的是快照隔离(Snapshot Isolation)。

更多技术文章,请访问:https://opensource.actionsky.com/

关于 SQLE

SQLE 是一款全方位的 SQL 质量管理平台,覆盖开发至生产环境的 SQL 审核和管理。支持主流的开源、商业、国产数据库,为开发和运维提供流程自动化能力,提升上线效率,提高数据质量。

✨ Github:https://github.com/actiontech/sqle

📚 文档:https://actiontech.github.io/sqle-docs/

💻 官网:https://opensource.actionsky.com/sqle/

👥 微信群:请添加小助手加入 ActionOpenSource

🔗 商业支持:https://www.actionsky.com/sqle

这篇关于OceanBase 的 Oracle 模式竟然可以使用 Repeatable Read?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1121211

相关文章

oracle 11g导入\导出(expdp impdp)之导入过程

《oracle11g导入导出(expdpimpdp)之导入过程》导出需使用SEC.DMP格式,无分号;建立expdir目录(E:/exp)并确保存在;导入在cmd下执行,需sys用户权限;若需修... 目录准备文件导入(impdp)1、建立directory2、导入语句 3、更改密码总结上一个环节,我们讲了

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解

《使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解》本文详细介绍了如何使用Python通过ncmdump工具批量将.ncm音频转换为.mp3的步骤,包括安装、配置ffmpeg环... 目录1. 前言2. 安装 ncmdump3. 实现 .ncm 转 .mp34. 执行过程5. 执行结

Java使用jar命令配置服务器端口的完整指南

《Java使用jar命令配置服务器端口的完整指南》本文将详细介绍如何使用java-jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助... 目录1. Java Jar文件简介1.1 什么是Jar文件1.2 创建可执行Jar文件2. 使用java

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

Java中的抽象类与abstract 关键字使用详解

《Java中的抽象类与abstract关键字使用详解》:本文主要介绍Java中的抽象类与abstract关键字使用详解,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、抽象类的概念二、使用 abstract2.1 修饰类 => 抽象类2.2 修饰方法 => 抽象方法,没有

MyBatis ParameterHandler的具体使用

《MyBatisParameterHandler的具体使用》本文主要介绍了MyBatisParameterHandler的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录一、概述二、源码1 关键属性2.setParameters3.TypeHandler1.TypeHa

Spring 中的切面与事务结合使用完整示例

《Spring中的切面与事务结合使用完整示例》本文给大家介绍Spring中的切面与事务结合使用完整示例,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录 一、前置知识:Spring AOP 与 事务的关系 事务本质上就是一个“切面”二、核心组件三、完

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

使用Python实现Word文档的自动化对比方案

《使用Python实现Word文档的自动化对比方案》我们经常需要比较两个Word文档的版本差异,无论是合同修订、论文修改还是代码文档更新,人工比对不仅效率低下,还容易遗漏关键改动,下面通过一个实际案例... 目录引言一、使用python-docx库解析文档结构二、使用difflib进行差异比对三、高级对比方