跳转至

DAO 分库机制与 Process 服务工厂

本文讲清 OBPM 数据访问层两大机制:Abstract*DAO → 每库一实现 的方言分库,与 ProcessFactory → *Process/*ProcessBean 的服务门面。基类体系见 [[entity-base-hierarchy]]。

1. DAO 三层结构(多数据库支持的核心)

以工作流实例 DAO 为例(全平台同构):

classDiagram
    class IRuntimeDAO {
        <<interface, core/common/dao>>
        通用 DAO 契约
    }
    class FlowStateRTDAO {
        <<interface>>
        实体专属契约
    }
    class AbstractFlowStateRTDAO {
        <<abstract>>
        手写 SQL 的主体
        getFullTableName() 抽象
    }
    class MysqlFlowStateRTDAO
    class OracleFlowStateRTDAO
    class PostgreSQLFlowStateRTDAO
    class HsqldbFlowStateRTDAO

    IRuntimeDAO <|.. AbstractFlowStateRTDAO
    FlowStateRTDAO <|.. AbstractFlowStateRTDAO
    AbstractFlowStateRTDAO <|-- MysqlFlowStateRTDAO
    AbstractFlowStateRTDAO <|-- OracleFlowStateRTDAO
    AbstractFlowStateRTDAO <|-- PostgreSQLFlowStateRTDAO
    AbstractFlowStateRTDAO <|-- HsqldbFlowStateRTDAO

各层职责

层 职责
IRuntimeDAO 平台级 DAO 契约(连接管理入口)
*DAO 接口(如 FlowStateRTDAO) 实体专属方法签名
Abstract*DAO SQL 主体写在这里(INSERT INTO T_FLOWSTATERT (ID,FLOWID,...) 列清单即表结构的权威来源);方言差异点抽为钩子
Mysql*DAO / Oracle*DAO / PostgreSQL*DAO / KingBase*DAO / DmSQL*DAO / OceanBase*DAO / Oscar*DAO / DB2*DAO / Hsqldb*DAO… 每库一个薄子类:只覆写分页 LIMIT、函数、schema 前缀(KingBase/OceanBase 常强制 PUBLIC.)、类型差异等钩子

要点:新增数据库 = 为每个 Abstract*DAO 派生一个薄子类 + 动态表侧增加一组 *Builder/*TableDefinition/*Validator(designtime/table/ddlutil/<db>/)。这也解释了为什么表结构文档(design/table-schema/core-tables.md)可以从 DAO 的 INSERT 列清单提取——SQL 就写在抽象层。

2. Process 服务工厂(业务门面)

DAO 之上是 Process 层——对外统一业务入口,ProcessFactory 按运行上下文创建:

classDiagram
    class ProcessFactory {
        <<obpm-core/util>>
        +getInstance() iProcessFactory$
        +createProcess(Class) AuthTimeService$
        +createRuntimeProcess(Class,...) RunTimeService$
    }
    class iProcessFactory {
        <<interface>>
    }
    class AuthTimeService {
        <<interface>>
        认证域服务 doCreate/doUpdate/...
    }
    class RunTimeService {
        <<interface>>
        运行域服务 + 事务
        beginTransaction/commit
    }
    class AbstractAuthTimeServiceImpl {
        <<abstract, E 泛型>>
    }
    class AbstractRunTimeServiceImpl {
        <<abstract>>
    }
    class UserProcess
    class UserProcessBean
    class DocumentProcess
    class DocumentProcessBean

    ProcessFactory --> iProcessFactory : 单例
    iProcessFactory <|.. AuthTimeService
    ProcessFactory ..> RunTimeService
    AuthTimeService <|-- AbstractAuthTimeServiceImpl
    RunTimeService <|-- AbstractRunTimeServiceImpl
    AbstractAuthTimeServiceImpl <|-- UserProcessBean
    UserProcess <|.. UserProcessBean
    AbstractRunTimeServiceImpl <|-- DocumentProcessBean
    DocumentProcess <|.. DocumentProcessBean

调用机制

flowchart TD
    A[Controller / iScript] -->|"ProcessFactory.createProcess(UserProcess.class)"| B[iProcessFactory 实现]
    B -->|按域路由| C[UserProcessBean<br/>AuthTime 线]
    B -->|按域路由| D[DocumentProcessBean<br/>RunTime 线]
    C --> E["按 dbType / 数据源<br/>new MysqlUserDAO / OracleUserDAO / …"]
    D --> F["AbstractDocStaticTblDAO 子类<br/>按 tabelType 写 TLK_ / LOG_"]
    E --> G[(系统库 T_USER 等)]
    F --> H[(业务库 TLK_ 动态表)]
概念 说明
AuthTimeService<E> 认证/组织域服务根接口(User/Department/Domain…),E 为实体泛型
RunTimeService<E> 运行域服务根接口,多出 beginTransaction/commitTransaction 事务边界(跨 DAO 组合写)
*Process 接口 每实体一份业务契约(UserProcess、DocumentProcess、TaskInfoProcess…),iScript 通过 getProcess() 系列拿到
*ProcessBean 实现类,继承两个抽象基类之一;内部再按数据库选 DAO——调用方永远不感知数据库类型

两条服务线的划分与继承主线一致:AuthTime 管组织/租户(数据在系统库),RunTime 管业务文档/流程(数据可在任意业务库)。ProcessFactory.createProcess vs createRuntimeProcess 的区别即在于此。

3. 设计时侧的平行机制

workspace 资源的读写不走 DAO 分库,而是 AbstractFSDesignTimeDAO(文件系统 DAO)+ DesignTimeServiceManager → 各 *DesignTimeServiceImpl(如 FormDesignTimeServiceImpl、ApplicationDesignTimeServiceImpl)。与 Process 层同构(Service 接口 + Impl + Manager 工厂),只是存储介质换成 XML 文件。见 [[../../workspace-mechanism/overview]]。