Skip to content

独立端点脚本开发与事务指南

本文档旨在指导开发者如何编写支持跨库事务的独立端点脚本 (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 示例场景

假设我们需要处理一个跨库业务:

  1. CRM 库 查询客户信息。
  2. Agent 库 查询规则配置。
  3. 同时更新 CRM 库的客户名称和 Agent 库的规则名称。
  4. 要求要么全部成功,要么全部失败(数据一致性)。

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 事务行为说明

  1. 自动开启 (Lazy Loading):

    • 在执行第 1、2 步查询时,系统不会开启事务,也不占用数据库连接。
    • 当执行第 3 步 update 时,系统识别到这是对 CRM 库的写操作,自动开启 CRM 库的事务。
    • 当执行第 4 步 update 时,系统识别到这是对 Agent 库的写操作,自动开启 Agent 库的事务。
  2. 原子性保证:

    • 如果第 3 步成功,但在第 4 步之前脚本抛出错误(或者第 4 步执行失败),系统会捕获异常并回滚 CRM 库的事务,确保数据不被部分修改。
  3. 开发建议:

    • 读写分离: 尽量将所有的 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 格式)中,可以对脚本的运行时行为进行微调。

配置项类型默认值说明
enableTransactionbooleantrue是否启用事务支持。
- true: 写操作会自动开启事务(推荐)。
- false: 所有操作直接执行,无事务保障,但适合纯查询或极致性能场景。

配置示例:

JSON
{
  "enableTransaction": true,
  "timeout": 5000
}

基于飞书知识库同步生成,内容以飞书源文档为准