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

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

k8s按需创建PV和使用PVC详解

《k8s按需创建PV和使用PVC详解》Kubernetes中,PV和PVC用于管理持久存储,StorageClass实现动态PV分配,PVC声明存储需求并绑定PV,通过kubectl验证状态,注意回收... 目录1.按需创建 PV(使用 StorageClass)创建 StorageClass2.创建 PV

Redis 基本数据类型和使用详解

《Redis基本数据类型和使用详解》String是Redis最基本的数据类型,一个键对应一个值,它的功能十分强大,可以存储字符串、整数、浮点数等多种数据格式,本文给大家介绍Redis基本数据类型和... 目录一、Redis 入门介绍二、Redis 的五大基本数据类型2.1 String 类型2.2 Hash

Redis中Hash从使用过程到原理说明

《Redis中Hash从使用过程到原理说明》RedisHash结构用于存储字段-值对,适合对象数据,支持HSET、HGET等命令,采用ziplist或hashtable编码,通过渐进式rehash优化... 目录一、开篇:Hash就像超市的货架二、Hash的基本使用1. 常用命令示例2. Java操作示例三

Linux创建服务使用systemctl管理详解

《Linux创建服务使用systemctl管理详解》文章指导在Linux中创建systemd服务,设置文件权限为所有者读写、其他只读,重新加载配置,启动服务并检查状态,确保服务正常运行,关键步骤包括权... 目录创建服务 /usr/lib/systemd/system/设置服务文件权限:所有者读写js,其他