建议将 JDBC 做成独立模块,并在实现前先补上“跨仓储事务”和“并发安全”两个能力;否则一次审批会拆成多次独立数据库操作,容易留下半完成流程。 1. 新建模块 ```text ordo-storage-jdbc/ ├── pom.xml └── src/main/ ├── java/com/jetlumen/ordo/storage/jdbc/ │ ├── JdbcTransactionExecutor.java │ ├── JdbcProcessDefinitionRepository.java │ ├── JdbcProcessInstanceRepository.java │ ├── JdbcApprovalTaskRepository.java │ ├── JdbcConnectionProvider.java │ └── mapper/ └── resources/db/migration/ └── V1__create_ordo_tables.sql ``` 依赖只需要 `ordo-api`、`javax.sql.DataSource` 和 JDBC 驱动;先不要依赖 Spring。 2. 先补事务边界 在 `ordo-api` 增加一个通用端口: ```java public interface TransactionExecutor { T execute(Supplier action); } ``` `DefaultOrdoEngine` 的 `start`、`approve`、`reject` 应在同一个事务中执行。 这保证: - 发起流程时,“创建实例 + 创建第一条任务”要么都成功,要么都回滚。 - 审批时,“完成旧任务 + 创建下一任务 / 结束实例”要么都成功,要么都回滚。 内存实现提供无操作事务执行器;JDBC 实现使用同一条线程绑定的 `Connection`,执行 `commit` 或 `rollback`。 3. 调整仓储 SPI 的并发语义 当前 `save` 是覆盖式写入,JDBC 下无法避免两个用户同时审批同一任务。建议在落 JDBC 前调整: ```java boolean insertIfAbsent(ProcessDefinition definition); boolean completeIfPending(ApprovalTask completedTask); ``` `completeIfPending` 对应 SQL: ```sql UPDATE ordo_approval_task SET status = ?, completed_at = ?, action_actor = ?, action_comment = ?, action_at = ? WHERE id = ? AND status = 'PENDING' ``` 受影响行数为 `0` 时,抛出 `TaskAlreadyCompletedException`。这比仅依赖 JVM 内的 `synchronized` 更可靠。 4. 数据库模型 采用规范化表,不把步骤和任务都塞进 JSON。 ```text ordo_process_definition - id varchar(64) primary key - name varchar(255) not null ordo_approval_step - definition_id varchar(64) not null - step_id varchar(64) not null - step_name varchar(255) not null - assignee varchar(255) not null - step_order integer not null - primary key (definition_id, step_id) ordo_process_instance - id varchar(36) primary key - definition_id varchar(64) not null - initiator varchar(255) not null - status varchar(32) not null - context_json text not null - started_at timestamp not null - finished_at timestamp null ordo_approval_task - id varchar(36) primary key - instance_id varchar(36) not null - step_id varchar(64) not null - task_name varchar(255) not null - assignee varchar(255) not null - status varchar(32) not null - created_at timestamp not null - completed_at timestamp null - action_actor varchar(255) null - action_comment text null - action_at timestamp null ``` 至少建立: ```text ordo_approval_task(instance_id) ordo_approval_task(status, assignee) ordo_process_instance(definition_id) ``` 5. `ProcessContext` 的持久化 `ProcessContext.variables` 适合存为 `context_json`。在 JDBC 模块内部使用 Jackson 做序列化与反序列化,不要让 `ordo-api` 依赖 Jackson。 v0.1 可以约定上下文仅支持 JSON 兼容值:字符串、数字、布尔值、列表、嵌套 Map。日期、枚举和自定义 Java 对象以后再通过可插拔 `ContextCodec` 解决。 6. JDBC 实现顺序 - 先写 `V1__create_ordo_tables.sql` - 实现 `JdbcTransactionExecutor` - 实现定义仓储与步骤读写 - 实现实例仓储及 `context_json` - 实现任务仓储及待办查询 - 调整 `DefaultOrdoEngine` 使用事务和条件更新 - 为 JDBC 仓储添加集成测试 7. 测试策略 先用 H2 快速验证 CRUD 和映射;并发条件更新、时间类型、唯一约束等最终应使用 Testcontainers 加 PostgreSQL 或 MySQL 验证。 建议第一版目标是 PostgreSQL;表结构、`timestamp` 语义和 JSON 支持都会更明确。等 JDBC 实现稳定后,再创建 Spring Boot Starter:Starter 只负责注入 `DataSource`、JDBC 仓储、事务执行器和 `DefaultOrdoEngine`。 帮忙按照这个实现一下JDBC模块