独立端点脚本开发与事务指南
本文档旨在指导开发者如何编写支持跨库事务的独立端点脚本 (Endpoint Scripts)。这类脚本拥有独立的 HTTP 访问入口,非常适合实现复杂的业务聚合逻辑。
1. 脚本定义
独立端点脚本是一种特殊的 JS 脚本,其类型为 ENDPOINT。
- API 路径:
/api/endpoint/{appCode}/{scriptName} - 请求方式:
POST - 请求体: JSON 对象,将直接作为
params传递给脚本。
2. 核心语法规范
所有独立端点脚本必须导出一个异步函数,并使用统一的 context.client SDK 进行数据操作。
2.1 函数签名
JavaScript
/**
* 独立端点入口函数
* @param {Object} params - HTTP 请求体中的 JSON 数据
* @param {Object} context - 执行上下文,包含用户信息、数据库访问能力等
*/
export default async function(params, context) {
// 业务逻辑...
}2.2 数据操作 SDK (context.client)
我们提供了一套符合直觉的链式 API 来操作数据集。无论底层数据集位于主库还是从库,API 的使用方式完全一致。
基本格式:await context.client.models.<dataset_code>.<operation>(args)
| 操作 | 说明 | 示例 |
|---|---|---|
findOne | 查询单条 | await ...models.user.findOne({ id: 1 }) |
create | 创建数据 | await ...models.user.create({ name: "John" }) |
update | 更新数据 | await ...models.user.update({ id: 1, age: 20 }) |
delete | 删除数据 | await ...models.user.delete({ id: 1 }) |
getList | 分页查询 | await ...models.user.getList({ page: 1, size: 10 }) |
注意: 所有数据库操作都是异步的,必须使用
await关键字等待结果。
3. 跨库事务实战
得益于底层的 Best Effort 1PC 事务机制,您无需在脚本中编写任何事务控制代码(如 begin, commit)。您只需按顺序编写业务逻辑,系统会自动处理事务的开启和提交。
3.1 示例场景
假设我们需要处理一个跨库业务:
- 从 CRM 库 查询客户信息。
- 从 Agent 库 查询规则配置。
- 同时更新 CRM 库的客户名称和 Agent 库的规则名称。
- 要求要么全部成功,要么全部失败(数据一致性)。
3.2 代码实现
JavaScript
/**
* 跨库事务测试脚本
* 脚本名称: transaction_demo
*/
export default async function transactionDemo(params, context) {
// ----------- 第一部分:数据查询 (读操作不开启事务) -----------
// 1. 查询 CRM 库 (dataset_crm_customer)
const customer = await context.client.models.dataset_680936453e5f491e8f36ef9169907808.findOne({
id: params.customerId
});
if (!customer) {
throw new Error("客户不存在");
}
// 2. 查询 Agent 库 (dataset_agent_rules)
const agentRules = await context.client.models.dataset_5d8190a1f74d43d0b605aad16a898ba3.findOne({
id: params.rulesId
});
if (!agentRules) {
throw new Error("规则不存在");
}
// ----------- 第二部分:数据更新 (写操作自动开启事务) -----------
// 系统检测到写操作,会自动开启对应数据库的事务。
// 注意:为了保证最佳的事务一致性,建议将所有的写操作放在脚本的后半部分集中执行。
// 3. 更新 CRM 库
await context.client.models.dataset_680936453e5f491e8f36ef9169907808.update({
id: customer.id,
customer_name: customer.customer_name + '_Updated'
});
// 4. 更新 Agent 库
// 此时,系统会自动开启第二个数据库的事务,并加入到当前会话中。
await context.client.models.dataset_5d8190a1f74d43d0b605aad16a898ba3.update({
id: agentRules.id,
name: agentRules.name + '_Updated'
});
// ----------- 脚本结束 -----------
// 脚本执行成功返回 -> 系统自动提交 CRM 库事务 -> 系统自动提交 Agent 库事务
// 脚本抛出异常 -> 系统自动回滚所有已开启的事务
return {
success: true,
message: "跨库更新成功",
updatedIds: [customer.id, agentRules.id]
};
}3.3 实际效果
发送 http post请求 api 端点路径
{
"customer_id": 22,
"agent_rules_id": 379
}
事务提交

事务回滚

3.4 事务行为说明
自动开启 (Lazy Loading):
- 在执行第 1、2 步查询时,系统不会开启事务,也不占用数据库连接。
- 当执行第 3 步
update时,系统识别到这是对 CRM 库的写操作,自动开启 CRM 库的事务。 - 当执行第 4 步
update时,系统识别到这是对 Agent 库的写操作,自动开启 Agent 库的事务。
原子性保证:
- 如果第 3 步成功,但在第 4 步之前脚本抛出错误(或者第 4 步执行失败),系统会捕获异常并回滚 CRM 库的事务,确保数据不被部分修改。
开发建议:
- 读写分离: 尽量将所有的
findOne/getList查询放在脚本开头,将create/update/delete写操作放在脚本结尾。这能缩短事务持有时间,提高并发性能。 - 参数校验: 在执行任何写操作之前,先进行充分的参数校验和业务逻辑判断。
- 读写分离: 尽量将所有的
4. 常见问题
Q: 我需要手动调用 commit 吗?
A: 不需要。只要脚本正常返回(没有抛出 Error),系统会自动提交所有事务。
Q: 如果我想回滚怎么办?
A: 直接 抛出异常 即可。
JavaScript
if (someCondition) {
throw new Error("业务条件不满足,回滚所有操作");
}Q: 支持多少个数据库同时操作?
A: 理论上没有限制。系统会根据你操作的数据集自动管理所有涉及的数据库连接。
5. 脚本配置 (Advanced)
在 app_script 表的 config 字段(JSON 格式)中,可以对脚本的运行时行为进行微调。
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enableTransaction | boolean | true | 是否启用事务支持。 - true: 写操作会自动开启事务(推荐)。 - false: 所有操作直接执行,无事务保障,但适合纯查询或极致性能场景。 |
配置示例:
JSON
{
"enableTransaction": true,
"timeout": 5000
}