---
title: "弱一致性读 - OceanBase 数据库 V4.6.0 | OceanBase 文档中心"
description: 弱一致性读 OceanBase 数据库提供了两种一致性级别（Consistency Level）：STRONG 和 WEAK。STRONG 指强一致性，读取最新数据，请求路由给主副本；WEAK 指弱一致性，不要求读取最新数据，请求优先路由给从副本。OceanBase 数据库的写操作始终是强一致性的，即始终由主副本提供…
---
切换语言

- 中文站 - 简体中文
- International - English
- 日本站 - 日本語

文档反馈![](https://mdn.alipayobjects.com/huamei_22khvb/afts/img/A*P8CuR4UJ_FkAAAAAAAAAAAAADiGDAQ/original) OceanBase 数据库分布式版 - V 4.6.0

# 弱一致性读

更新时间：2026-07-14 17:41:38

[编辑](https://github.com/oceanbase/oceanbase-doc/edit/V4.6.0/zh-CN/700.reference/100.oceanbase-database-concepts/800.transaction-management/200.transaction-concurrency-and-consistency/500.weak-consistency-reading.md)  

OceanBase 数据库提供了两种一致性级别（Consistency Level）：STRONG 和 WEAK。STRONG 指强一致性，读取最新数据，请求路由给主副本；WEAK 指弱一致性，不要求读取最新数据，请求优先路由给从副本。OceanBase 数据库的写操作始终是强一致性的，即始终由主副本提供服务；读操作默认是强一致性的，由主副本提供服务，用户也可以指定弱一致性读，由从副本优先提供服务。

## 一致性级别的指定方式

有两种方式指定一致性级别：

- 通过 `ob_read_consistency` 系统变量指定

     - 设置 Session 变量，影响当前 Session

      ```sql
      obclient> SET ob_read_consistency = WEAK;
      obclient> SELECT * FROM t1;  -- 弱一致性读

      ```
     - 设置 Global 变量，影响之后新建的所有 Session

      ```sql
      obclient> SET GLOBAL ob_read_consistency = STRONG;

      ```
 - 指定 Hint 方式

     - 指定 WEAK Consistency，优先级高于 `ob_read_consistency`

      ```sql
      obclient> SELECT /*+READ_CONSISTENCY(WEAK) */ * FROM t1;

      ```
     - 指定 STRONG Consistency

      ```sql
      obclient> SELECT /*+READ_CONSISTENCY(STRONG) */ * FROM t1;

      ```

## SQL 语句的一致性级别

- 写语句 DML (INSERT/DELETE/UPDATE)：强制使用 STRONG Consistency，要求基于最新数据进行修改。
 - `SELECT FOR UPDATE`（SFU）：与写语句类似，强制使用 STRONG Consistency。
 - 只读语句 `SELECT`：用户可以配置不同的 Consistency Level，满足不同的读取需求。

## 事务的一致性级别

弱一致性读的最佳实践是为不在事务中的 SELECT 语句指定 WEAK 一致性级别，它的语义是确定的。对于显式开启事务的场景，语法上，OceanBase 数据库允许不同的语句配置不同的一致性级别，这样会让用户很困惑，而且如果使用不当，SQL 会报错。

原则：

- 一致性级别的最低设置为语句级别。当会话或语句上标记为弱读时，系统将尝试采用弱读路径。
 - 写语句和SFU语句只能使用强读，即使存在弱读标记，这些语句仍将按强读方式执行。
 - 在一个事务中，如果首先执行了写语句或 SFU 语句，后续的读语句若需读取本事务的未提交修改，则必须以强读方式执行。

下面举例说明。

```sql
BEGIN;
-- 修改语句，consistency_level=STRONG，整个事务应该是 STRONG
insert into t1 values (1);

-- SQL自身的 consistency_level=WEAK，但由于第一条语句为 STRONG，
-- 因此这条语句的 consistency_level 强制设置为 STRONG
select /*+READ_CONSISTENCY(WEAK) */ * from t1;
COMMIT;

BEGIN;
-- SFU属于修改语句，consistency_level=STRONG，整个事务应该也是 STRONG
select * from t1 for update;

BEGIN;
-- 第一条语句为 WEAK
select /*+READ_CONSISTENCY(WEAK) */ * from t1;

-- 在 Session 或全局的 ob_read_consistency 未设置为WEAK的情况下，该语句可正常以 Strong Read 的形式执行
select * from t1;
COMMIT;

-- 修改语句，必须为 STRONG，该语句可正常执行
insert into t1 values (1);

-- SQL自身的 consistency_level=WEAK，但由于前一条语句是一个修改语句，
-- 因此这条语句的 consistency_level 强制设置为 STRONG
select /*+READ_CONSISTENCY(WEAK) */ * from t1;
COMMIT;

```

因此，对于单条 SQL 而言，一致性级别的确定规则优先级从大到小可以概括为：

1. 根据语句类型确定的一致性级别，例如 DML 和 SFU 必须采用 STRONG。
 2. 事务的一致性级别，如果语句在事务中，而且不是第一条语句，则采用事务的一致性级别。
 3. 通过 Hint 指定的一致性级别。
 4. 系统变量指定的一致性级别。
 5. 缺省采用 STRONG。

## 与隔离级别关系

- STRONG 支持所有的隔离级别。
 - WEAK 仅支持读已提交 `READ COMMITTED` 隔离级别，其他隔离级别下会报错 `OB_NOT_SUPPORTED`。
 - 隔离级别为 `Repeatable Read` 和 `Serializable` 时执行弱读请求也生效。

## 弱一致性读配置项

### V2.2.x 之前的版本

| 名称 | 范围 | 语义 |
| --- | --- | --- |
| enbale_causal_order_read | 集群级 | 是否开启单调读，默认为 false |
| max_stale_time_for_weak_consistency | 集群级 | 弱一致性读最大落后时间，默认值是 5 秒 |

V2.2.x 之前的版本仅支持 Proxy 级别的单调读，即只要客户端始终访问同一个 Proxy，就可以保证单调读。具体实现方式是在 Proxy 上维护单调递增的弱一致性读版本号。如果客户端跨 Proxy 访问，则不保证单调读。如果用户需要集群级别单调读，则需要使用 V2.2.x 及之后的版本。

### V2.2.x ~ V3.x 版本

| 名称 | 范围 | 语义 |
| --- | --- | --- |
| enable_monotonic_weak_read | 租户级 | 是否开启单调读，默认为 True |
| max_stale_time_for_weak_consistency | 租户级 | 弱一致性读最大落后时间，默认值是 5 秒 |
| weak_read_version_refresh_interval | 集群级 | 弱一致性读版本号刷新周期，默认值 50 毫秒 |

各个配置项具体含义如下：

- `enable_monotonic_weak_read` ：租户级单调读开关

  弱一致性读会路由到不同副本上，不同副本上读到的数据新旧没有保证；单调读开关打开后，OceanBase 数据库保证读到的数据版本不回退，保证单调性。一个典型的应用场景是保证因果序：两个事务 T1 和 T2，T1 提交之后，T2 才提交，如果客户端读到了 T2 事务的修改，那么之后一定可以读到 T1 事务的修改。
 - `max_stale_time_for_weak_consistency`：弱一致性读最大落后时间

  OceanBase 数据库弱一致性读提供有界旧保证，即保证读到的数据最多落后 `max_stale_time_for_weak_consistency` 时间，默认配置值是 5 秒，支持租户级配置。

  正常情况下，各个分区的备副本落后时间在 100 毫秒到 200 毫秒，弱一致性读的时效性在百毫秒级别；当出现网络抖动、无主等情况，弱一致性读的时效性会降低，一旦一个副本落后时间超过 `max_stale_time_for_weak_consistency`，该副本将不可读，内部重试机制会重试其他有效副本；如果所有副本都不可读，则持续重试，直到语句超时。

  当开启单调读开关后，OceanBase 数据库内部会为每个租户维护一个 Cluster 级别的弱一致性读版本号，该版本号也满足 `max_stale_time_for_weak_consistency` 约束。它的生成方式是统计租户下所有分区副本回放进度的最小值，如果某些分区副本落后时间超过 `max_stale_time_for_weak_consistency`，则不统计该副本。目前机制下，一个落后的副本会影响整体单调读的版本号，例如有两个分区的两个副本，一个副本落后 100ms，一个副本落后 1 秒，那么整体的单调读版本号是 1 秒。我们认为副本长时间落后不会是常态，正常情况下，单调读版本号都应该在百毫秒级别。
 - `weak_read_version_refresh_interval`：弱一致性读版本号刷新周期

  弱一致性读版本号刷新周期影响读取数据的新旧程度，它配置的值不能大于 `max_stale_time_for_weak_consistency`。当它配置为 0 时，弱一致性单调读功能关闭，即不再维护 Cluster 级别弱一致性读版本号。另外，它是集群级别配置项，不支持租户级别配置。

### V4.x 版本

对于 4.x 版本，`max_stale_time_for_weak_consistency` 和 `weak_read_version_refresh_interval` 两个配置项的功能保持与之前的版本一致。

## 弱一致性读时间戳

弱一致性读，通常是指从副本、备库上的查询语句。OceanBase 数据库的弱一致性读依旧返回事务一致性点, 不会出现返回未提交事务和一半事务的情况。

弱一致性读时间戳，包括两个方面：

- 弱读执行之前，需要确定一个读快照数据。
 - 分区自身实时维护一个最大安全可读的位点，凡是读快照大于该位点的读请求，均不能读该副本。

### 时间戳生成方式

OceanBase 数据库弱读一致性分为两大类：单调读和非单调读。不同的能力，时间戳生成的方式不同。

**单调读**

单调读是指根据读请求发起的绝对时间，后发起的请求使用的读快照一定不比前者小，确保读到的数据不会出现回退。这里的单调是针对语句读快照而言的。单调读的保证依赖集群级别单调弱读版本号，全局版本号需要做到不回退。

全局版本号的生成来源于每个 OBServer 节点维护的最小最大安全版本号，该版本号的生成依赖本机日志同步的进度。对于 OceanBase 数据库而言，事务的日志数据，由三个模块来维护，`apply service`、`replay_service` 和 `Transaction`：

1. `apply service` 负责事务日志的本地落盘、发送备机、接收 Leader 同步的日志等操作。对备机而言，它为每个日志流维护了一个滑动窗口，将收到的日志，按照 logid 从小到大管理起来。日志从滑动窗口中顺序滑出，提交给 `replay_service` 去回放。
 2. `replay_service` 负责日志的回放，它将同一个事务的多条日志 Hash 到同一个工作线程，保证同一个事务的日志顺序回放，但是同一个分区的多个事务是并发回放的。对一个分区的日志而言，日志按照提交时间戳有序串到链表中，由多个线程并发回放。
 3. `Transaction` 负责事务状态的管理，`Transaction` 执行日志的回放操作，即将 Redo 数据回放到 MemStore，并记录事务的状态。

由上描述可知，一条日志从 `apply service` 接收到提交 `replay_service` 回放任务，再通过 `Transaction` 回放事务日志，为保证单个分区备机读不会读到一半的事务，需要找到该分区备机读的安全版本号，保证该版本号之前的所有事务都已经回放完成。计算公式如下：

`slave_read_ts = min(replay_service_ts, apply_service_ts, trans_service_ts) - 1`

其中：

- `apply_service_ts` 表示 `apply service` 滑动窗口中下一条将要滑出或将要生成的日志 Timestamp。
 - `replay_service_ts` 表示该日志流尚未回放日志的 Timestamp 最小值。
 - `trans_service_ts` 表示当前所有正在回放事务的 `prepare_log_ts` 的最小值。

举例说明：假设 `apply service` 的滑动窗口中存在两条日志，logid 和日志的提交时间戳分别为（10，100），（11，200）；`replay_service` 中，该日志流尚未回放的日志分别为`（7，70），（8，80）`；`Transaction` 中，只有一个正在回放的事务，刚刚回放完 redo 和 prepare log，并且 `prepare log` 的 logid 为 `9`，`prepare_log_ts`＝90；此时该分区的 `安全版本号＝min(100, 70, 90) - 1 = 69`。

**非单调读**

相对于单调读，非单调读保证的能力较弱。非单调读则不保证前后发起的请求快照递增，由于同一份数据不同副本同步进度的差异，如果前后两次读取不同的副本，数据可能出现回退。

### 原子性

无论采用单调读还是非单调读，V3.x 及之前版本均可保证同一事务在单个分区内数据修改的原子性；V4.x 及以上版本均可保证同一事务在单个日志流内数据修改的原子性。

原子性保证遵循以下原则：当读快照小于单个分区或日志流维护的最大安全可读版本号时，读取到的数据一定具备原子性。

 上一篇 下一篇 ![有帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*y6ocSqN8cqsAAAAAAAAAAAAAARQnAQ)![无帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*BG9IQJyLHF8AAAAAAAAAAAAAARQnAQ)![反馈](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*eTWdQKCRKHwAAAAAAAAAAAAAARQnAQ)[AI](https://www.oceanbase.com/obi) 咨询热线
