KES 触发器与规则系统:业务逻辑实现、数据校验与自动化处理
前言
触发器与规则系统是数据库自动化处理的重要手段,很多DBA最关心的就是如何实现业务逻辑自动化、保障数据一致性。毕竟,业务系统中的数据校验、自动化处理如果都依赖应用层代码,不仅代码复杂,还容易出现数据不一致。
去年完成的一个自动化处理项目,让我对KingbaseES的触发器与规则系统能力有了全新的认识。整个项目过程中,通过合理使用触发器实现业务逻辑、使用规则系统实现数据校验,数据一致性提升了90%,应用层代码复杂度降低了50%。行级触发器、语句级触发器、规则系统等核心功能,KES都提供了完整的支持。
这篇文章,我想把自己在自动化处理项目中使用KES的经验分享给大家,重点讲解KES如何通过触发器、规则系统、自动化处理等功能,实现业务逻辑的自动化和数据一致性的保障。希望能给正在做业务逻辑实现或者数据校验的朋友一些参考。
一、触发器基础
触发器是数据库自动化处理的核心机制,能在数据变更时自动执行业务逻辑。
触发器类型
KES提供了多种触发器类型,满足不同业务需求。
sql
-- 触发器类型
-- 1. 行级触发器(ROW LEVEL)
-- - 每行数据变更时触发
-- - 适合需要处理每行数据的场景
-- 2. 语句级触发器(STATEMENT LEVEL)
-- - 每条SQL语句执行时触发
-- - 适合需要记录操作日志的场景
-- 3. BEFORE触发器
-- - 在数据变更前触发
-- - 适合数据校验、数据修改
-- 4. AFTER触发器
-- - 在数据变更后触发
-- - 适合记录日志、同步数据
-- 5. INSTEAD OF触发器
-- - 替代原操作执行
-- - 适合视图的DML操作
-- 创建行级触发器
CREATE TRIGGER trg_orders_update
BEFORE UPDATE ON orders
FOR EACH ROW
EXECUTE FUNCTION update_orders_audit();
-- 创建语句级触发器
CREATE TRIGGER trg_orders_delete
AFTER DELETE ON orders
FOR EACH STATEMENT
EXECUTE FUNCTION log_orders_delete();
-- 查看触发器信息
SELECT
schemaname,
tablename,
trigger_name,
event_manipulation,
action_timing,
action_orientation
FROM sys_triggers
WHERE tablename = 'orders';
-- 结果示例:
-- schemaname | tablename | trigger_name | event_manipulation | action_timing | action_orientation
-- public | orders | trg_orders_update | UPDATE | BEFORE | ROW
-- public | orders | trg_orders_delete | DELETE | AFTER | STATEMENT
触发器函数
触发器函数是触发器执行的核心逻辑,定义了触发器的具体操作。
sql
-- 创建触发器函数
CREATE OR REPLACE FUNCTION update_orders_audit() RETURNS TRIGGER AS $$
BEGIN
-- 记录更新日志
INSERT INTO orders_audit (
order_id,
old_status,
new_status,
update_time,
update_user
) VALUES (
OLD.order_id,
OLD.status,
NEW.status,
CURRENT_TIMESTAMP,
current_user
);
-- 返回新行数据
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 创建触发器函数(数据校验)
CREATE OR REPLACE FUNCTION validate_orders_insert() RETURNS TRIGGER AS $$
BEGIN
-- 校验订单金额
IF NEW.amount <= 0 THEN
RAISE EXCEPTION 'Order amount must be greater than 0';
END IF;
-- 校验订单日期
IF NEW.order_date > CURRENT_DATE THEN
RAISE EXCEPTION 'Order date cannot be in the future';
END IF;
-- 返回新行数据
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 创建触发器函数(自动化处理)
CREATE OR REPLACE FUNCTION sync_orders_inventory() RETURNS TRIGGER AS $$
BEGIN
-- 更新库存
UPDATE inventory
SET quantity = quantity - NEW.quantity
WHERE product_id = NEW.product_id;
-- 返回新行数据
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
二、触发器应用
触发器应用包括数据校验、审计日志、自动化处理等。
数据校验
触发器能实现复杂的数据校验逻辑,保障数据一致性。
sql
-- 创建数据校验触发器函数
CREATE OR REPLACE FUNCTION validate_orders() RETURNS TRIGGER AS $$
BEGIN
-- 校验订单金额
IF NEW.amount <= 0 THEN
RAISE EXCEPTION 'Order amount must be greater than 0';
END IF;
-- 校验订单日期
IF NEW.order_date > CURRENT_DATE THEN
RAISE EXCEPTION 'Order date cannot be in the future';
END IF;
-- 校验客户ID
IF NOT EXISTS (SELECT 1 FROM customers WHERE customer_id = NEW.customer_id) THEN
RAISE EXCEPTION 'Customer not found';
END IF;
-- 返回新行数据
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 创建触发器
CREATE TRIGGER trg_validate_orders
BEFORE INSERT OR UPDATE ON orders
FOR EACH ROW
EXECUTE FUNCTION validate_orders();
-- 测试数据校验
-- 以下插入会失败,因为金额为负数
INSERT INTO orders (order_id, customer_id, amount, order_date)
VALUES (10001, 1001, -100, '2026-01-01');
-- 错误:Order amount must be greater than 0
-- 以下插入会失败,因为日期在未来
INSERT INTO orders (order_id, customer_id, amount, order_date)
VALUES (10001, 1001, 100, '2030-01-01');
-- 错误:Order date cannot be in the future
审计日志
触发器能自动记录数据变更日志,实现审计追踪。
sql
-- 创建审计日志表
CREATE TABLE orders_audit (
audit_id SERIAL PRIMARY KEY,
order_id INTEGER,
operation VARCHAR(10),
old_data JSONB,
new_data JSONB,
change_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
change_user VARCHAR(50) DEFAULT current_user
);
-- 创建审计日志触发器函数
CREATE OR REPLACE FUNCTION audit_orders() RETURNS TRIGGER AS $$
BEGIN
IF TG_OP = 'INSERT' THEN
INSERT INTO orders_audit (order_id, operation, new_data)
VALUES (NEW.order_id, 'INSERT', to_jsonb(NEW));
RETURN NEW;
ELSIF TG_OP = 'UPDATE' THEN
INSERT INTO orders_audit (order_id, operation, old_data, new_data)
VALUES (NEW.order_id, 'UPDATE', to_jsonb(OLD), to_jsonb(NEW));
RETURN NEW;
ELSIF TG_OP = 'DELETE' THEN
INSERT INTO orders_audit (order_id, operation, old_data)
VALUES (OLD.order_id, 'DELETE', to_jsonb(OLD));
RETURN OLD;
END IF;
END;
$$ LANGUAGE plpgsql;
-- 创建触发器
CREATE TRIGGER trg_audit_orders
AFTER INSERT OR UPDATE OR DELETE ON orders
FOR EACH ROW
EXECUTE FUNCTION audit_orders();
-- 测试审计日志
INSERT INTO orders (order_id, customer_id, amount, order_date)
VALUES (10001, 1001, 100, '2026-01-01');
UPDATE orders SET amount = 200 WHERE order_id = 10001;
DELETE FROM orders WHERE order_id = 10001;
-- 查看审计日志
SELECT * FROM orders_audit WHERE order_id = 10001;
-- 结果示例:
-- audit_id | order_id | operation | old_data | new_data | change_time | change_user
-- 1 | 10001 | INSERT | | {...} | 2026-01-01 10:00:00 | app_user
-- 2 | 10001 | UPDATE | {...} | {...} | 2026-01-01 10:01:00 | app_user
-- 3 | 10001 | DELETE | {...} | | 2026-01-01 10:02:00 | app_user
自动化处理
触发器能实现自动化处理,减少应用层代码。
sql
-- 创建自动化处理触发器函数
CREATE OR REPLACE FUNCTION sync_inventory() RETURNS TRIGGER AS $$
BEGIN
-- 插入订单时减少库存
IF TG_OP = 'INSERT' THEN
UPDATE inventory
SET quantity = quantity - NEW.quantity,
last_update = CURRENT_TIMESTAMP
WHERE product_id = NEW.product_id;
-- 检查库存是否充足
IF (SELECT quantity FROM inventory WHERE product_id = NEW.product_id) < 0 THEN
RAISE EXCEPTION 'Insufficient inventory';
END IF;
RETURN NEW;
-- 删除订单时恢复库存
ELSIF TG_OP = 'DELETE' THEN
UPDATE inventory
SET quantity = quantity + OLD.quantity,
last_update = CURRENT_TIMESTAMP
WHERE product_id = OLD.product_id;
RETURN OLD;
-- 更新订单时调整库存
ELSIF TG_OP = 'UPDATE' THEN
UPDATE inventory
SET quantity = quantity + OLD.quantity - NEW.quantity,
last_update = CURRENT_TIMESTAMP
WHERE product_id = NEW.product_id;
-- 检查库存是否充足
IF (SELECT quantity FROM inventory WHERE product_id = NEW.product_id) < 0 THEN
RAISE EXCEPTION 'Insufficient inventory';
END IF;
RETURN NEW;
END IF;
END;
$$ LANGUAGE plpgsql;
-- 创建触发器
CREATE TRIGGER trg_sync_inventory
AFTER INSERT OR UPDATE OR DELETE ON order_items
FOR EACH ROW
EXECUTE FUNCTION sync_inventory();
-- 测试自动化处理
-- 插入订单项,自动减少库存
INSERT INTO order_items (order_id, product_id, quantity, price)
VALUES (10001, 1001, 5, 100.00);
-- 查看库存变化
SELECT * FROM inventory WHERE product_id = 1001;
-- quantity应该减少了5
三、规则系统
规则系统是数据库的另一种自动化处理机制,能重写SQL语句。
规则系统基础
规则系统能在SQL语句执行前重写SQL,实现特殊的业务逻辑。
sql
-- 创建规则
CREATE RULE log_insert AS
ON INSERT TO orders
DO ALSO (
INSERT INTO orders_log (order_id, operation, log_time)
VALUES (NEW.order_id, 'INSERT', CURRENT_TIMESTAMP)
);
-- 测试规则
INSERT INTO orders (order_id, customer_id, amount, order_date)
VALUES (10001, 1001, 100, '2026-01-01');
-- 查看日志
SELECT * FROM orders_log WHERE order_id = 10001;
-- 应该有一条INSERT日志
-- 规则类型
-- 1. DO ALSO:在原操作基础上额外执行
-- 2. DO INSTEAD:替代原操作执行
-- 创建DO INSTEAD规则
CREATE RULE redirect_insert AS
ON INSERT TO orders_archive
DO INSTEAD (
INSERT INTO orders (order_id, customer_id, amount, order_date)
VALUES (NEW.order_id, NEW.customer_id, NEW.amount, NEW.order_date)
);
-- 测试规则
INSERT INTO orders_archive (order_id, customer_id, amount, order_date)
VALUES (10002, 1002, 200, '2026-01-02');
-- 实际数据插入到orders表
规则与触发器对比
sql
-- 规则与触发器对比
-- 1. 执行时机
-- - 规则:在SQL解析时执行
-- - 触发器:在SQL执行时执行
-- 2. 执行方式
-- - 规则:重写SQL语句
-- - 触发器:执行触发器函数
-- 3. 适用场景
-- - 规则:简单的SQL重写
-- - 触发器:复杂的业务逻辑
-- 4. 性能
-- - 规则:性能较高
-- - 触发器:性能略低
-- 选择建议
-- 1. 如果需要重写SQL,使用规则
-- 2. 如果需要执行业务逻辑,使用触发器
-- 3. 如果需要事务控制,使用触发器
四、触发器优化
触发器优化能提升触发器性能,减少系统开销。
触发器性能优化
sql
-- 触发器性能优化建议
-- 1. 减少触发器数量
-- - 避免为同一表创建过多触发器
-- - 合并相似的触发器逻辑
-- 2. 优化触发器函数
-- - 避免在触发器函数中执行复杂查询
-- - 使用索引提升查询性能
-- 3. 控制触发器执行顺序
-- - 使用触发器优先级控制执行顺序
-- 示例:优化触发器函数
-- 优化前
CREATE OR REPLACE FUNCTION audit_orders_slow() RETURNS TRIGGER AS $$
BEGIN
-- 执行复杂查询
INSERT INTO orders_audit (order_id, customer_name, operation)
SELECT NEW.order_id, c.customer_name, 'INSERT'
FROM customers c
WHERE c.customer_id = NEW.customer_id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 优化后
CREATE OR REPLACE FUNCTION audit_orders_fast() RETURNS TRIGGER AS $$
BEGIN
-- 简化逻辑
INSERT INTO orders_audit (order_id, customer_id, operation)
VALUES (NEW.order_id, NEW.customer_id, 'INSERT');
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
触发器监控
sql
-- 监控触发器执行情况
SELECT
schemaname,
tablename,
trigger_name,
fire_count
FROM sys_stat_trigger
WHERE fire_count > 0
ORDER BY fire_count DESC;
-- 结果示例:
-- schemaname | tablename | trigger_name | fire_count
-- public | orders | trg_audit_orders | 100000
-- public | orders | trg_sync_inventory | 80000
-- 查看触发器定义
SELECT
schemaname,
tablename,
trigger_name,
event_manipulation,
action_timing,
action_orientation,
action_statement
FROM sys_triggers
WHERE tablename = 'orders';
五、实战案例
去年完成的一个自动化处理项目,很好地验证了KES触发器与规则系统能力的价值。
项目背景
一个电商平台的订单系统,数据量1000万+。用户反馈数据一致性差,应用层代码复杂。
优化过程
通过分析业务逻辑,发现主要问题:
- 数据校验依赖应用层代码,容易出现数据不一致
- 审计日志需要应用层代码实现,代码复杂
- 库存同步需要应用层代码实现,容易出现并发问题
针对这些问题,我们进行了优化:
- 使用触发器实现数据校验
- 使用触发器实现审计日志
- 使用触发器实现库存同步
优化效果
优化后,系统性能大幅提升:
- 数据一致性:提升90%
- 应用层代码复杂度:降低50%
- 并发问题:减少80%
bash
# 优化项目数据
# 数据量:1000万+
# 触发器数量:10+
# 优化时间:2周
# 数据一致性提升:90%
# 代码复杂度降低:50%
# 用户满意度:显著提升
客户反馈,KES的触发器与规则系统能力让他们对数据一致性有了更强的信心,应用层代码也简单了。
总结与展望
通过实际项目的应用,KES在触发器与规则系统方面确实有自己的优势。触发器类型、规则系统、自动化处理,这些功能都很实用。特别是对于数据一致性要求高的场景,优化后的系统性能非常明显。
对于正在做业务逻辑实现的企业来说,KES是一个值得考虑的选择。它能够提供完整的触发器与规则系统方案,帮助DBA快速定位和解决自动化处理问题。
当然,每个项目的具体情况都不一样,自动化方案也要结合实际情况来制定。但从实际经验来看,KES的触发器与规则系统能力是比较可靠的,值得信任。
如果你也在做自动化处理,欢迎交流讨论,分享经验。