翻这套工业数据 WebApi 的数据层时,我发现它在同时伺候三座库房:SQL Server、PostgreSQL,还有一座信创场景下的某国产数据库。
一套工业数据采集中枢,要落地的数据既要在老系统里读,也要在新平台里写,还得满足信创替换的要求。于是三种方言被塞进了同一个代码库。ts03 那篇写过它怎么搭起来的,我这篇想说代价。
(等价改写,名字换掉了)为了盖住三种方言,仓库侧有一个统一的提供入口:
// 不同库房走各自的实现,但对外只露一个口
public interface IRepositoryProvider { }
// SQL Server / PostgreSQL / 某国产库 各有一份实现
方言是最先绊脚的
三种库不是"换个连接串就行"。分页写法不一样,某国产库对大小写和关键字的容忍度跟另两家不同,自增主键的生成方式也各搞一套。同一句查询,落到不同库房要翻译成不同样子。我没法确认每一处适配是哪次需求逼出来的,但更可能的情况是:先接一家,后来要兼容下一家,于是补丁越叠越厚。
事务的语义悄悄分了家
最隐蔽的是事务。三家对隔离级别、对"写一半回滚"的默认行为并不完全一致。同样一段落库逻辑,在一家跑得好好的,换一家可能偶发锁等待或写入顺序错位。这种问题不会在编译期冒头,只在生产环境的某个时刻冷不丁出现。
心智负担是长期的
为了统一,代码里有一个仓库提供入口,全仓有 94 处 RepositoryProvider 相关的引用。这个数字本身说明:抽象是有的,但抽象之下的三套语义,每个改动的工程师都得在脑子里同时装下。新人接手第一关,往往不是业务逻辑,而是"这一段到底落在哪座库房、用哪套方言"。
一套代码伺候三种库房,换来的是迁移时的弹性;代价是每个人都要替三座库房记笔记。值不值,得看那座信创库房是不是非换不可——但对已经背着它跑的系统来说,先把三套语义的差异记清楚,比急着统一更重要。