datai/datai-scenes/datai-scene-salesforce/docs/decisions/2026-02-02-002-02-ADR-Apex代码编译和执行技术选型.md

4.3 KiB
Raw Permalink Blame History

ADR-002-02: Apex 代码编译和执行技术选型

状态

已接受

日期

2026-02-02

背景

Apex 代码编译和执行功能需要选择合适的技术方案,满足以下要求:

  1. 支持编译 Apex 类、触发器、编译并测试、执行匿名代码
  2. 支持查询编译历史、测试结果、代码覆盖率
  3. 保证多线程安全
  4. 与现有架构保持一致
  5. 支持历史数据查询和审计

决策

决策 1数据持久化策略

选择方案 1使用数据库持久化MySQL理由如下

  1. 支持历史数据查询和审计需求
  2. 数据可靠性高,避免内存丢失
  3. 支持复杂的查询条件(时间范围、类型筛选等)
  4. 与现有 MyBatis Plus 技术栈一致
  5. 支持分页查询,性能可控

放弃方案 2仅使用内存缓存的理由

  1. 服务重启后数据丢失
  2. 不支持历史数据查询
  3. 内存占用随数据量增加
  4. 无法满足审计需求

决策 2结果处理方式

选择方案 1直接使用 apex.jar 原生类,理由如下:

  1. 与 Salesforce API 完全兼容
  2. 减少不必要的封装层,降低复杂度
  3. 避免类型转换开销
  4. 与现有 Partner 模块保持一致的设计原则
  5. 代码更简洁,维护成本低

放弃方案 2创建自定义封装层的理由

  1. 增加不必要的抽象层
  2. 需要维护额外的转换逻辑
  3. 增加开发工作量
  4. 与现有架构风格不一致

决策 3并发控制策略

选择方案 1使用 ReentrantLock理由如下

  1. 灵活性高,支持可中断、超时、公平锁等特性
  2. 性能优于 synchronized在竞争激烈时
  3. 支持条件变量,便于实现复杂的同步逻辑
  4. 与现有代码风格一致

放弃方案 2synchronized 关键字)的理由:

  1. 灵活性较低
  2. 不支持超时机制
  3. 性能在竞争激烈时不如 ReentrantLock

放弃方案 3数据库乐观锁的理由

  1. 增加数据库开销
  2. 需要额外维护版本号字段
  3. 对于编译操作,不需要严格的事务隔离

决策 4数据库表设计

选择方案 14 张独立表(编译历史、测试结果、测试失败、代码覆盖率),理由如下:

  1. 符合数据库范式,避免数据冗余
  2. 每张表职责单一,易于维护
  3. 支持灵活的查询需求
  4. 与现有表设计规范一致

放弃方案 2单表存储所有数据的理由

  1. 表结构复杂,字段过多
  2. 存在大量空值,浪费存储空间
  3. 查询性能差
  4. 不符合数据库设计规范

后果

正面影响

  1. 数据可靠性:使用数据库持久化,数据不会丢失
  2. 查询灵活性:支持复杂的历史数据查询
  3. 代码简洁性:直接使用原生类,减少封装层
  4. 性能可控ReentrantLock 提供高性能的并发控制
  5. 维护成本低:与现有架构保持一致,开发人员熟悉
  6. 扩展性好:独立表设计便于后续扩展

负面影响

  1. 数据库开销:需要维护 4 张表,增加数据库负担
  2. 存储成本:历史数据需要占用存储空间
  3. 查询性能:大数据量时查询性能可能下降(可通过索引优化)
  4. 复杂度增加:需要处理数据库事务和并发控制

替代方案

方案 A使用 Redis 缓存

  • 优点:查询速度快,支持过期策略
  • 缺点:数据可能丢失,不支持复杂查询,增加系统复杂度
  • 适用场景:对查询速度要求极高,可接受数据丢失的场景

方案 B使用 MongoDB

  • 优点:灵活的文档模型,适合存储非结构化数据
  • 缺点:增加新的技术栈,学习成本高,与现有架构不一致
  • 适用场景:数据结构多变,需要灵活存储的场景

方案 C使用消息队列异步处理

  • 优点:解耦编译操作和持久化操作,提高响应速度
  • 缺点:增加系统复杂度,需要处理消息丢失问题
  • 适用场景:高并发场景,对响应速度要求高的场景

相关文档