【金仓数据库】ksql 指南(七) —— 启动和管理事务(KingbaseES 数据一致性保障)

引言

在实际业务当中,不少操作要"多步同步完成或者同步失败",就像转账时,从A账户扣款并给B账户入账,如果仅仅扣了款却没有入账,就会引发数据错误,所以要用"事务"来保证数据的一致性,本文就"ksql命令行运作事务"展开论述,按照"事务概念------基本操作------隔离级别------问题查找"的顺序层层分解,利用通俗易懂的语言和实际业务案例(比如转账)加以阐述,使得初学者也能够领会事务的关键意义及其操作手段。

文章目录

  • 引言
    • 一、前置准备:确认操作环境(衔接前文,确保示例可落地)
      • [1.1 1. 用有权限的用户连接数据库](#1.1 1. 用有权限的用户连接数据库)
      • [1.2 2. 确认测试表与数据(用转账场景的表为例)](#1.2 2. 确认测试表与数据(用转账场景的表为例))
    • [二、核心概念:事务与 ACID 特性(新手必懂)](#二、核心概念:事务与 ACID 特性(新手必懂))
    • [三、事务控制命令:3 个核心命令玩转事务](#三、事务控制命令:3 个核心命令玩转事务)
      • [3.1 1. 启动事务:BEGIN / START TRANSACTION](#3.1 1. 启动事务:BEGIN / START TRANSACTION)
      • [3.2 2. 提交事务:COMMIT(确认操作,永久生效)](#3.2 2. 提交事务:COMMIT(确认操作,永久生效))
      • [3.3 3. 回滚事务:ROLLBACK(撤销操作,恢复原状)](#3.3 3. 回滚事务:ROLLBACK(撤销操作,恢复原状))
      • [3.4 4. 事务的 "自动提交" 特性(新手必知坑)](#3.4 4. 事务的 “自动提交” 特性(新手必知坑))
    • [四、事务隔离级别:解决 "多事务干扰" 问题](#四、事务隔离级别:解决 “多事务干扰” 问题)
      • [4.1 1. 先懂问题:隔离级别要解决什么?](#4.1 1. 先懂问题:隔离级别要解决什么?)
      • [4.2 2. KingbaseES 支持的隔离级别(4 种)](#4.2 2. KingbaseES 支持的隔离级别(4 种))
      • [4.3 3. 隔离级别操作:查看与修改](#4.3 3. 隔离级别操作:查看与修改)
        • [3.1 查看当前隔离级别](#3.1 查看当前隔离级别)
        • [3.2 修改隔离级别(当前会话生效)](#3.2 修改隔离级别(当前会话生效))
        • [3.3 隔离级别效果演示(以 REPEATABLE READ 为例)](#3.3 隔离级别效果演示(以 REPEATABLE READ 为例))
    • [五、查看与管理活跃事务:避免 "锁表" 问题](#五、查看与管理活跃事务:避免 “锁表” 问题)
      • [5.1 1. 查看活跃事务(用系统视图 pg_stat_activity)](#5.1 1. 查看活跃事务(用系统视图 pg_stat_activity))
      • [5.2 2. 终止异常事务(需管理员权限)](#5.2 2. 终止异常事务(需管理员权限))
    • [六、常见问题排查:事务操作的 "高频坑"](#六、常见问题排查:事务操作的 “高频坑”)
      • [问题 1:事务未提交导致锁表,其他事务无法修改](#问题 1:事务未提交导致锁表,其他事务无法修改)
      • [问题 2:隔离级别过低导致脏读](#问题 2:隔离级别过低导致脏读)
      • [问题 3:事务回滚后数据丢失(误以为提交了)](#问题 3:事务回滚后数据丢失(误以为提交了))
      • [问题 4:执行 DDL 语句后事务自动提交](#问题 4:执行 DDL 语句后事务自动提交)
    • 七、总结:事务使用的核心建议

一、前置准备:确认操作环境(衔接前文,确保示例可落地)

事务操作依赖已有的表和数据,需先完成以下准备,避免示例执行失败:

1.1 1. 用有权限的用户连接数据库

事务操作包含INSERTUPDATEDELETE等,执行这些操作时,用户要具有表操作的权限,推荐以管理员用户system或者像前面创建的test这样的被授权用户来建立连接,其中test要有test_schema.sys_user表的UPDATE权限。

bash 复制代码
# 连接 kingbase 数据库,用户为 system
ksql -d kingbase -U system
# 切换到 test_schema 模式(使用前文创建的表)
SET search_path TO test_schema, public;

1.2 2. 确认测试表与数据(用转账场景的表为例)

为了靠近实际业务,我们形成"账户表 account"(用以取代复杂场景),而且加入测试数据(后面会用转账例子来阐述事务)。

sql 复制代码
# 1. 创建账户表(id:账户ID,balance:余额)
CREATE TABLE IF NOT EXISTS account (
    id INT PRIMARY KEY,
    balance NUMERIC(10,2) NOT NULL CHECK (balance >= 0) -- 余额不能为负
);
# 2. 插入测试数据(A账户1000元,B账户2000元)
INSERT INTO account (id, balance) VALUES (1, 1000.00), (2, 2000.00);
# 3. 验证数据(确认初始余额正确)
SELECT * FROM account;

执行后若显示以下结果,说明准备完成:

二、核心概念:事务与 ACID 特性(新手必懂)

在学习操作之前,要先领会"事务"的实质,所谓事务,就是"一组无法分割的SQL操作",这个组的操作或者全部执行完毕(提交),或者全部不执行(回滚),不存在仅部分执行的情况。事务应具备ACID特性,这是数据一致性的关键保障,可以用"转账场景"来简单阐述:

后续所有事务操作,都是围绕 "保障 ACID 特性" 展开的。

三、事务控制命令:3 个核心命令玩转事务

KingbaseES经由BEGIN(开始), COMMIT(提交), ROLLBACK(回滚)这3个命令来控制事务,其操作较为简单,不过一定要严格按照流程来,下面结合"转账示例"详细阐述一下。

3.1 1. 启动事务:BEGIN / START TRANSACTION

在执行一系列"原子操作"之前,首先要启动事务,并告知数据库"后续的操作将形成一个整体"
语法(两种写法均可):

sql 复制代码
BEGIN; -- 推荐,简洁
-- 或
START TRANSACTION;

示例(启动转账事务):

sql 复制代码
# 1. 启动事务
BEGIN;
# 2. 执行转账操作(A账户id=1扣200,B账户id=2加200)
UPDATE account SET balance = balance - 200 WHERE id = 1; -- A扣款
UPDATE account SET balance = balance + 200 WHERE id = 2; -- B入账

执行后,事务处于 "未提交" 状态,此时数据仅在当前会话可见(其他会话看不到修改),需执行 COMMITROLLBACK 结束事务。

3.2 2. 提交事务:COMMIT(确认操作,永久生效)

执行完毕之后,事务就会处于"未提交"的状态,在这种情况下,数据只会出现在当前会话当中(其他会话无法看到这些改动),而且必须要执行 COMMIT 或者 ROLLBACK 来结束事务。
语法

sql 复制代码
COMMIT;

示例(提交转账事务):

sql 复制代码
# 1. 提交事务(让扣款和入账永久生效)
COMMIT;
# 2. 验证结果(查看A、B账户余额)
SELECT * FROM account;

执行结果(符合预期,总金额仍为 3000):

3.3 3. 回滚事务:ROLLBACK(撤销操作,恢复原状)

事务中的某一步如果出现错误,比如在转账的时候把B账户ID写错了,造成入账失败,那么就要执行ROLLBACK来撤销所有的操作,使得数据回到事务开始之前的状态,然后事务就结束了。
语法

sql 复制代码
ROLLBACK;

示例(模拟错误并回滚):

sql 复制代码
# 1. 先恢复初始数据(A=1000,B=2000)
UPDATE account SET balance = 1000 WHERE id = 1;
UPDATE account SET balance = 2000 WHERE id = 2;

# 2. 启动新事务,模拟错误(B账户ID写成3,不存在)
BEGIN;
UPDATE account SET balance = balance - 200 WHERE id = 1; -- A扣款成功(余额800)
UPDATE account SET balance = balance + 200 WHERE id = 3; -- B账户不存在,执行失败

# 3. 查看错误(ksql会提示"0 rows updated",说明入账失败)
# 4. 回滚事务(撤销A的扣款,恢复到初始状态)
ROLLBACK;

# 5. 验证结果(A余额回到1000,B仍为2000)
SELECT * FROM account;

执行结果(数据恢复,无损失):

3.4 4. 事务的 "自动提交" 特性(新手必知坑)

KingbaseES 默认情况下,"自动提交"(auto_commit = on)会被打开,也就是说,每次执行 INSERT/UPDATE/DELETE 语句时,数据库都会自动隐式提交事务,就像是每条语句都是单独的事务一样。
查看自动提交状态

sql 复制代码
SHOW auto_commit;

关闭自动提交(适合多步操作需作为事务的场景):

sql 复制代码
SET auto_commit = off;

提醒 :关闭自动提交后,所有操作需手动 COMMIT 才生效,若关闭会话未提交,会自动回滚。

四、事务隔离级别:解决 "多事务干扰" 问题

若众多事务一同操作同一组数据,则有可能产生"脏读""不可重复读""幻读"之类的问题,KingbaseES凭借"事务隔离级别"来控制事务之间的隔离水平,KingbaseES具备4种标准的隔离级别,应当按照业务需求加以选用。

4.1 1. 先懂问题:隔离级别要解决什么?

用 "两个事务操作同一张表" 的场景,解释常见问题:

4.2 2. KingbaseES 支持的隔离级别(4 种)

不同隔离级别解决的问题不同,性能也不同(隔离级别越高,性能越低),默认级别为 READ COMMITTED

4.3 3. 隔离级别操作:查看与修改

3.1 查看当前隔离级别
sql 复制代码
SHOW TRANSACTION ISOLATION LEVEL;

默认结果read committed

3.2 修改隔离级别(当前会话生效)

语法

sql 复制代码
SET TRANSACTION ISOLATION LEVEL 隔离级别;

示例 1:修改为 REPEATABLE READ(解决不可重复读):

sql 复制代码
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

示例 2:修改为 SERIALIZABLE(金融场景):

sql 复制代码
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

提醒 :修改隔离级别后,需重新启动事务(BEGIN)才会生效。

3.3 隔离级别效果演示(以 REPEATABLE READ 为例)

用两个 ksql 会话(会话 A、会话 B)演示 "不可重复读" 的解决:

  1. 会话 A :设置隔离级别为 REPEATABLE READ,启动事务,查询 A 账户余额:

    sql 复制代码
    SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
    BEGIN;
    SELECT balance FROM account WHERE id = 1; -- 结果:1000.00
  2. 会话 B:修改 A 账户余额并提交:

    sql 复制代码
    BEGIN;
    UPDATE account SET balance = 900 WHERE id = 1;
    COMMIT;
    SELECT balance FROM account WHERE id = 1; -- 结果:900.00
  3. 会话 A:再次查询 A 账户余额(仍为 1000.00,解决不可重复读):

    sql 复制代码
    SELECT balance FROM account WHERE id = 1; -- 结果:1000.00(不受会话B影响)
    COMMIT; -- 提交后,再次查询会显示900.00

五、查看与管理活跃事务:避免 "锁表" 问题

如果事务长时间未提交,比如在执行 BEGIN 之后忘记了 COMMITROLLBACK,那么就会锁定相关的表或者行,使得其他的事务无法执行修改操作,要掌握如何查看这些异常活跃的事务,并知道如何去终止它们。

5.1 1. 查看活跃事务(用系统视图 pg_stat_activity)

sql 复制代码
SELECT 
    pid, -- 事务进程ID
    usename, -- 执行事务的用户
    datname, -- 数据库名
    query, -- 事务执行的SQL
    state -- 事务状态(active=活跃)
FROM pg_stat_activity 
WHERE state = 'active' AND query LIKE 'BEGIN%' OR query LIKE 'UPDATE%';

结果解读 :若看到 query 包含 BEGIN/UPDATEstate=active,说明是未提交的活跃事务。

5.2 2. 终止异常事务(需管理员权限)

若某事务长时间活跃(如 pid=1234),执行以下命令终止:

sql 复制代码
SELECT pg_terminate_backend(1234); -- 1234 为事务的 pid

验证:终止后,原事务会自动回滚,锁定的表 / 行会释放。

六、常见问题排查:事务操作的 "高频坑"

问题 1:事务未提交导致锁表,其他事务无法修改

报错信息

plaintext 复制代码
ERROR:  could not obtain lock on row in relation "account"
DETAIL:  Process 1234 is holding the lock.

原因 :进程 1234 的事务未提交,锁定了 account 表的行。
解决方案

  1. 查看活跃事务,找到锁定进程的 pid(如 1234):

    sql 复制代码
    SELECT pid, query FROM pg_stat_activity WHERE relation = 'account'::regclass;
  2. 终止该进程:

    sql 复制代码
    SELECT pg_terminate_backend(1234);

问题 2:隔离级别过低导致脏读

场景 :事务 A 读到事务 B 未提交的修改,后来事务 B 回滚,事务 A 的数据错误。
原因 :当前隔离级别为 READ UNCOMMITTED(允许脏读)。
解决方案 :将隔离级别提升到 READ COMMITTED 及以上:

sql 复制代码
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

问题 3:事务回滚后数据丢失(误以为提交了)

场景 :执行 UPDATE 后未 COMMIT,断开会话再连接,数据恢复原状。
原因 :KingbaseES 对未提交的事务,断开会话时会自动回滚。
解决方案 :事务操作完成后,务必执行 COMMIT 确认提交,可通过 SELECT 验证结果。

问题 4:执行 DDL 语句后事务自动提交

场景 :在事务中执行 CREATE TABLE 后,之前的 UPDATE 被自动提交,无法回滚。
原因 :KingbaseES 中 DDL 语句(CREATE/ALTER/DROP)会隐式触发 COMMIT,终止当前事务。
解决方案 :事务中避免混合 DDL 和 DML(INSERT/UPDATE/DELETE)操作,若需执行 DDL,单独作为一个事务。

七、总结:事务使用的核心建议

本文完整覆盖了事务的 "概念→操作→隔离级别→问题排查",核心建议可总结为:

  1. 记住事务三个命令:"BEGIN"开始,"COMMIT"确认,"ROLLBACK"撤销,防止出现"未提交"或者"误回滚"的情况。
  2. 隔离级别依需求选定 :普通业务采用默认的 READ COMMITTED,统计用途 REPEATABLE READ,而金融类则选用 SERIALIZABLE 来兼顾性能与一致性。
  3. 避免长时间事务:启动事务后尽快完成操作并提交,防止锁表影响其他业务;
  4. DML/DDL 分开用:DDL 会自动提交,不要和 DML 放在同一事务中。

掌握事务运作之后,你就具有了 KingbaseES 数据一致性保障的关键能力,到此为止,关于从"连接数据库"到"事务控制"的整个 ksgl 命令行操作的讲解就完毕了,可以应对多数 KingbaseES 的日常运作情况,如果想要进一步深入学习,可以留意后面进阶的部分(比如分区表,备份还原等),如果有期待学习的内容,可以直接在评论区留言或者给我发私信。

相关推荐
Java面试题总结15 小时前
MongoDB(70)如何使用副本集进行备份?
数据库·mongodb
荒川之神15 小时前
Oracle LEVEL 函数练习(HR 模式 employees 表)
数据库·oracle
TDengine (老段)16 小时前
TDengine IDMP 工业数据建模 —— 元素与数据查询
大数据·数据库·人工智能·物联网·时序数据库·tdengine·涛思数据
蜡台16 小时前
Mysql 安装与配置
数据库·mysql
lajidecrd16 小时前
Ubuntu24安装PostgreSQL和PgVector
数据库·postgresql
羊小猪~~16 小时前
Redis学习笔记(数据类型、持久化、事件、管道、发布订阅等)
开发语言·数据库·c++·redis·后端·学习·缓存
福娃筱欢16 小时前
Oracle迁移KES提示ERROR: type “geometry“ does not exist
数据库·oracle
mldlds16 小时前
使用 Qt 插件和 SQLCipher 实现 SQLite 数据库加密与解密
数据库·qt·sqlite
大空大地202616 小时前
Entity Framework
数据库
王仲肖16 小时前
PostgreSQL 事务 ID 年龄增长与冻结机制分析
数据库·postgresql