05-customer-sql-override.md 5.97 KB

切片 5 — 扩展:每客户 SQL 覆盖

元数据驱动框架能表达的内容是有限的。

客户可能需要销售对账报表使用不同聚合规则,需要一个独特的自定义视图支撑成本看板,或需要一个行为从根本上偏离标准的存储过程。覆盖表(切片 4)可以加字段和覆盖 SQL 片段,但不能替换存储过程的逻辑;过程是代码,不是数据。

到达这个边界时,xly 的逃生口是:把手写 SQL 文件提交到 script/客户/<customer-name>/,并直接应用到该客户 schema。这完全绕过元数据层。它是生产中真实使用的通道,适用于若干客户;Wiki 必须诚实记录其范围、成本、适用时机和运维纪律。

记录对象

客户 重庆展印
覆盖文件 script/客户/重庆展印/Sp_SalSalesCheck.sql(723 行)
替换内容 标准 Sp_SalSalesCheck 存储过程(销售对账列表)
配套文件 script/客户/重庆展印/viw_salsaleschecking_pro.sql(该过程读取的自定义视图)
部署 手工,由工程师 / DBA 对该客户 schema 应用

文件开头两行说明了这个通道的形状:

DROP PROCEDURE IF EXISTS `Sp_SalSalesCheck`;
delimiter ;;
CREATE PROCEDURE `Sp_SalSalesCheck`(IN sLoginId varchar(100), ...)

标准过程被 drop,自定义过程取而代之。gdsmodule 中的元数据仍按名称引用该过程(sProcName = 'Sp_SalSalesCheck');运行时照常调用。差异完全存在于过程主体中,而主体现在是工程师编写的变体。

当前代码库中有覆盖的客户

script/客户/ 下有 18 个客户子目录:

统兴       重庆展印   嘉诚      安徽金印   万昌
无锡中江   扬州浩宇   金九      亚明威     快马
金宣发     千彩       高旺      朝阳       上海亚峰
湛江新澳   福雅       远传

每个目录有一到十几个 .sql 文件。多数是自定义过程(Sp_*)和自定义视图(viw_*)。读取目录列表本身就是系统文档:这里的客户和功能,是框架无法表达、需要 bespoke 行为的地方。

覆盖如何进入系统

没有自动通道。搜索 Java 代码中加载 script/客户 或遍历这些目录的部署服务,没有结果。机制是运维性的:

  1. 工程师以标准过程为起点编写覆盖 .sql 并修改主体。
  2. 文件提交到 script/客户/<customer>/,用于可追溯性。
  3. 使用 mysql --defaults-file=... < the-file.sql 或等价方式,手工对目标客户 MySQL schema 执行。
  4. 从那以后,该客户 schema 中的过程主体就不同于其他客户;框架代码不变。

把文件放在代码库中很重要:工程团队可以一眼看出哪些客户偏离标准。但这不表示这些文件会作为任何 build 的一部分发布。

为什么这不同于切片 4

切片 4 的 gdsconfigformcustomslave 和切片 1 的元数据 Add/Update 路径都留在框架内部。客户特定行为是叠加在共享代码库之上:每个租户运行时读取相同 Java、相同 MyBatis mapper、相同标准过程。

切片 5 的通道位于框架之下。客户 schema 中有一个同名但主体不同的存储过程。调用 Sp_SalSalesCheck 的 Java / MyBatis 代码不知道另一端是标准过程还是重庆展印变体。框架不知道,也无法分辨。

因此覆盖具有:

  • 强能力。 MySQL 存储过程 SQL 能写出的任何东西,都可替换标准行为。
  • 运维脆弱。 客户 schema 重建、恢复或迁移时,覆盖必须重新应用或保持存活。它不跟随代码库备份,只跟随数据库备份。
  • 推理困难。 维护人员读标准 Sp_SalSalesCheck 源码时,必须记得某些客户实时 DB 上同名过程是另一段代码。stack trace 和“这个过程做什么”取决于你连到哪个 schema。

经验规则:优先选择切片 4 的元数据定制。只有元数据模型确实无法表达客户需求时,才使用切片 5 SQL 覆盖。

重庆展印 Sp_SalSalesCheck 的不同点

文件顶部显示:

  • 它从 SysSystemSettings 读取 'CbxSrcNoCheck' 行,决定哪些计费类型进入销售对账报表。这是标准过程可能没有暴露的客户特定开关。
  • 它调用全局 Fun_GetLookCustomer(sLoginId, sBrId, sSuId) helper 做权限作用域,与标准过程一致。
  • 它接受与标准过程相同的参数列表(sLoginId / sCustomerId / sBrId / sSuId / bFilter / pageNum / pageSize 等),因此框架调用点不变。

未来修订可以与标准 Sp_SalSalesCheck 做并排 diff,精确解释分歧业务规则。当前最重要的是结构事实:过程形状和参数列表与标准一致,主体不同。

配套视图 viw_salsaleschecking_pro.sql 也出于同一原因存在:当覆盖需要标准没有的 join 形状时,工程师编写客户特定视图,并与过程一起应用到该客户 schema。

本切片引入的概念

  • 两条定制通道:通过后台编辑元数据(切片 1、2、4)vs. 直接应用到客户 schema 的原始 SQL 覆盖。
  • 客户间 schema 分歧:同一过程名在不同客户 DB 中可能表示不同过程,影响维护人员分析运行时行为。

参考项

应新增维护人员页:每客户 SQL 覆盖,记录 script/客户/<customer>/ 约定、手工应用流程、运维影响和审计模式。

待验证项

  1. 脚本应用是否真的完全手工? 还是存在 Quartz job / DbToDbController 机制?需要读 DbToDbServiceImpl.java 确认。
  2. 审计。 写小脚本连接客户 DB,把每个 Sp_* / viw_* 主体与标准 diff。意外分歧是运维风险。
  3. 并排 Sp_SalSalesCheck diff。 当前只描述结构,未来应纳入实际主体差异,说明重庆展印改变了哪条业务规则以及原因。
  4. 生命周期。 客户升级、恢复、重建 schema 时,每个覆盖如何重新应用?部署章节需要 runbook。