---
title: OceanBase 数据库中的行锁问题排查指南-OceanBase数据库使用指南
description: 了解OceanBase数据库在实际应用中关于OceanBase 数据库中的行锁问题排查指南相关的常见问题和使用技巧，帮助您快速解决OceanBase 数据库中的行锁问题排查指南的难题。
---
切换语言

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

划线反馈

# OceanBase 数据库中的行锁问题排查指南

更新时间：2026-06-10 09:51

适用版本： V2.1.x、V2.2.x、V3.1.x、V3.2.x 内容类型：Troubleshoot  

本文介绍行锁问题的排查思路，并提供部分排查案例。

## 适用版本

OceanBase 数据库所有版本

## 锁冲突问题的排查思路

在业务环境中，可以将锁抽象为两个与行锁有密切关系的对象，即行锁的持有者与等待者。而行锁的持有者与等待者都是事务的一部分，因此在监控活跃事务中监控锁的持有者与等待者会对锁冲突的问题排查提供很大的帮助。

OceanBase 数据库提供了以下虚拟表，分别用于监控活跃事务、行锁持有者与行锁等待者。

- `__all_virtual_trans_stat`：用于监控活跃事务。

  各主要表列的说明如下表所示。

  | 列名 | 说明 |
  | --- | --- |
  | svr_ip | 表示创建该事务上下文的 OBServer 的 IP 地址。 |
  | session_id | 表示该事务上下文所属会话的唯一 ID。 |
  | proxy_id | 表示客户端 OBProxy/Java Client 对应的 IP 地址与端口号。 |
  | trans_id | 表示该事务的唯一 ID。 |
  | is_existing | 表示当前事务上下文是否正在退出。 |
  | partition | 表示当前事务上下文在哪个分区上创建。 |
  | participants | 当前事务的参与者列表。 |
  | ctx_create_time | 事务上下文的创建时间。 |
  | ref | 表示事务上下文当前的引用计数。 |
  | sql_no | 表示当前事务上下文上最后一次执行的 SQL 的 `sql_no`。 |
  | state | 表示事务上下文当前的状态。 可能的状态有 `INIT`、`PREPARE`、`COMMIT`、`ABORT` 与 `CLEAR`。 |
  | part_trans_action | 表示该事务上下文上最后执行的动作。 可能的状态有 `START_TASK`、`END_TASK`、`COMMIT`。 |
  | lock_for_read_entry_count | 表示该事务在表扫描过程中遇到锁冲突重试的次数。 |
 - `__all_virtual_trans_lock_stat`：记录了当前集群中所有活跃事务持有行锁的相关信息。

  | 列名 | 说明 |
  | --- | --- |
  | rowkey | 表示持有锁的行的 rowkey。 |
  | session_id | 持有锁的事务所属的会话唯一 ID。 |
  | proxy_id | 表示持有锁的事务所属客户端 OBProxy/Java Client 对应的 IP 地址与端口号。 |
  | trans_id | 表示持有锁的事务的唯一 ID。 |
 - `__all_virtual_lock_wait_stat`：统计了当前集群中所有等待行锁的请求或语句的相关信息。

  | 列名 | 说明 |
  | --- | --- |
  | session_id | 等待锁的事务所属的会话唯一 ID。 |
  | proxy_id | 表示等待锁的事务所属客户端 OBProxy/Java Client 对应的 IP 地址与端口号。 |
  | trans_id | 表示等待锁的事务的唯一 ID。 |
  | lock_ts | 表示该请求开始等待锁的时间点。 |
  | abs_timeout | 表示等待锁的语句的绝对超时时间。 |
  | try_lock_times | 表示等待锁的语句重试加锁的次数。 |
  | block_session_id | 表示在该行第一个等待事务的 `session_id`。 |

#### 说明

等待锁分为两种情况，即写写冲突与读写冲突。对于读写冲突的情况，是由于事务中读语句的 `read_snapshot_version` 大于写语句的 `prepare_version`，但 `commit_version` 不能确定，因此需要等待写事务完成后才能读到写语句的修改。

`_all_virtual_lock_wait_stat` 表中主要用于展示写写冲突的情况，对于读写冲突，仅会使用 `_all_virtual_trans_stat` 中的 `part_trans_action` 与 `lock_for_read_retry_count` 字段来表示。如果`part_trans_action` 的值为 `START_TASK`，且 `lock_for_read_retry_count` 的值非零，则可以判断是发生了读写冲突。

## 锁冲突问题的排查案例

### 场景一

业务使用了较大的超时事件，且存在一个会话中的未知长事务持有锁，阻塞了其他事务的执行，需要找到并停止该长事务。

- 方案一：通过无法加锁的事务查询持有锁的事务。

     1. 通过无法加锁的事务的 `session_id`，找到等待锁的行的 `rowkey`。

       可以发现等待锁的事务在等待主键为 `pk` 的行。

       ```shell
       obclient> select * from __all_virtual_lock_wait_stat where session_id = 3221580756\G
       *************************** 1. row ***************************
                 svr_ip: xxx.xxx.xx.xxx
              svr_port: xxxx
               table_id: 1101710651081554
                 rowkey: table_id=1101710651081554 hash=779dd9b202397d7 rowkey_object=[{"VARCHAR":"pk", collation:"utf8mb4_general_ci"}]
                   addr: 140433355180784
              need_wait: 1
                recv_ts: 1600440077959302
                lock_ts: 1600440077960167
            abs_timeout: 1600450077859302
         try_lock_times: 1
        time_after_recv: 1307610861
             session_id: 3221580756
       block_session_id: 3221580756
                   type: 0
              lock_mode: 0
       1 row in set (0.01 sec)

       ```
     2. 通过主键找到对应持有该行行锁的事务的 `session_id`。

       发现持有行锁的事务的 `session_id` 为 `3221577520`。

       ```shell
       obclient> select * from __all_virtual_trans_lock_stat where rowkey like '%pk%'\G
       *************************** 1. row ***************************
             tenant_id: 1002
              trans_id: {hash:6605492148156030705, inc:3284929, addr:"xxx.xxx.xx.xxx:xxxx", t:1600440036535233}
                svr_ip: xxx.xxx.xx.xxx
              svr_port: xxxx
             partition: {tid:1101710651081554, partition_id:0, part_cnt:0}
              table_id: 1101710651081554
                rowkey: table_id=1101710651081554 hash=779dd9b202397d7 rowkey_object=[{"VARCHAR":"pk", collation:"utf8mb4_general_ci"}]
            session_id: 3221577520
              proxy_id: NULL
       ctx_create_time: 2020-09-18 22:41:03.583285
          expired_time: 2020-09-19 01:27:16.534919
       1 row in set (0.05 sec)

       ```
     3. 根据查到的 `session_id` 停止该事务的会话。

       ```shell
       obclient> KILL 3221577520

       ```
 - 方案二：通过查询长事务。

     1. 根据事务执行时间，找到执行时间最长且未结束事务的 `trans_id`。

       ```shell
       obclient> select * from __all_virtual_trans_lock_stat order by ctx_create_time limit 5\G
       *************************** 1. row ***************************
             tenant_id: 1002
              trans_id: {hash:6605492148156030705, inc:3284929, addr:"xxx.xxx.xx.xxx:xxxx", t:1600440036535233}
                svr_ip: xxx.xxx.xx.xxx
              svr_port: xxxx
             partition: {tid:1101710651081554, partition_id:0, part_cnt:0}
              table_id: 1101710651081554
                rowkey: table_id=1101710651081554 hash=779dd9b202397d7 rowkey_object=[{"VARCHAR":"pk", collation:"utf8mb4_general_ci"}]
            session_id: 3221577520
              proxy_id: NULL
       ctx_create_time: 2020-09-18 22:41:03.583285
          expired_time: 2020-09-19 01:27:16.534919
       1 row in set (0.05 sec)

       ```
     2. 通过事务的 `trans_id` 找到其所持有的所有锁，并根据 `rowkey` 明确哪一个是需要停止的服务。

       下例中，第一行的 `rowkey` 与上面查询的 `rowkey` 相同，因此该事务即是持有锁的事务。

       ```shell
       obclient> select * from __all_virtual_trans_lock_stat where trans_id like '%hash:6605492148156030705, inc:3284929%'\G
       *************************** 1. row ***************************
             tenant_id: 1002
              trans_id: {hash:6605492148156030705, inc:3284929, addr:"xxx.xxx.xx.xxx:xxxx", t:1600440036535233}
                svr_ip: xxx.xxx.xx.xxx
              svr_port: xxxx
             partition: {tid:1101710651081554, partition_id:0, part_cnt:0}
              table_id: 1101710651081554
                rowkey: table_id=1101710651081554 hash=779dd9b202397d7 rowkey_object=[{"VARCHAR":"pk", collation:"utf8mb4_general_ci"}]
            session_id: 3221577520
              proxy_id: NULL
       ctx_create_time: 2020-09-18 22:41:03.583285
          expired_time: 2020-09-19 01:27:16.534919
       *************************** 2. row ***************************
             tenant_id: 1002
              trans_id: {hash:6605492148156030705, inc:3284929, addr:"xxx.xxx.xx.xxx:xxxx", t:1600440036535233}
                svr_ip: xxx.xxx.xx.xxx
              svr_port: xxxx
             partition: {tid:1101710651081554, partition_id:0, part_cnt:0}
              table_id: 1101710651081554
                rowkey: table_id=1101710651081554 hash=89413aecf767cd7 rowkey_object=[{"VARCHAR":"ob", collation:"utf8mb4_general_ci"}]
            session_id: 3221577520
              proxy_id: NULL
       ctx_create_time: 2020-09-18 22:41:03.583285
          expired_time: 2020-09-19 01:27:16.534919
       2 rows in set (0.05 sec)

       ```
     3. 确认要停止的事务的 `session_id` 后，停止对应事务的会话。

       ```shell
       obclient> KILL 3221577520;
       Query OK, 0 rows affected (0.00 sec)

       ```

### 场景二

业务反馈某一行上执行的事务总超时，已知该行的 `rowkey`，本场景以 `rowkey` 包含字符串 `test` 为例。

1. 根据 `rowkey` 查询 `__all_virtual_trans_lock_stat` 表找到对应的持锁事务。

   ```shell
   obclient> select * from __all_virtual_trans_lock_stat where memtable_key like '%test%'\G;
   *************************** 1. row ***************************
         tenant_id: 1
          trans_id: {hash:6124095709354809361, inc:249476, addr:"xxx.xxx.xx.xxx:xxxx", t:1529075759177984}
            svr_ip: xxx.xxx.xx.xxx
          svr_port: xxxx
         partition: {tid:1099511677778, partition_id:0, part_cnt:0}
      memtable_key: {table_id:1099511677778, hash_val:7893135555906369137, buf:"table_id=1099511677778 hash=3fb183d083d6d9f1 rowkey_object=[{"VARCHAR":"test", collation:"utf8mb4_general_ci"}] "}
        session_id: 2147549190
          proxy_id: NULL
   ctx_create_time: 2018-06-15 23:16:35.695821
      expired_time: 2018-06-15 23:32:39.177533
   1 row in set (0.03 sec)

   ```
 2. 根据上述结果，查询活跃事务虚拟表 `__all_virtual_trans_stat` 找到对应的事务的 `trans_id` 等信息。

   ```shell
   OceanBase (root@oceanbase)> select * from __all_virtual_trans_stat where session_id= 2147549190 \G;
   *************************** 1. row ***************************
                   tenant_id: 1
                      svr_ip: xxx.xxx.xx.xxx
                    svr_port: xxxx
                     inc_num: 249476
                  session_id: 2147549190
                    proxy_id: NULL
                  trans_type: 0
                    trans_id: {hash:6124095709354809361, inc:249476, addr:"xxx.xxx.xx.xxx:xxxx", t:1529075759177984}
                  is_exiting: 0
                 is_readonly: 0
                  is_decided: 0
     active_memstore_version: 0-0-0
                   partition: {tid:1099511677778, partition_id:0, part_cnt:0}
                participants: [{tid:1099511677778, partition_id:0, part_cnt:0}]
                  autocommit: 0
           trans_consistency: 0
             ctx_create_time: 2018-06-15 23:16:35.695821
                expired_time: 2018-06-15 23:32:39.177533
                       refer: 1073741826
                      sql_no: 1
                       state: 0
           part_trans_action: 2
   lock_for_read_retry_count: 1
   1 row in set (0.01 sec)

   ```shell
   obclient> KILL 2147549190;
   Query OK, 0 rows affected (0.00 sec)

   ```

上一篇

[如何配置 OceanBase 数据库的请求锁超时的时间](https://www.oceanbase.com/knowledge-base/oceanbase-database-20000011704)

下一篇

[OceanBase 的 IN_queue_time 是否包含行锁等待的耗时](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000000267163) ![有帮助](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) 咨询热线
