Files
hsm-database-certs-compare/需求文档.md
T
cheney fe28ddeaac feat: HSM main/slave certificate comparison with batch SQL generation
- compare usercert_tab by subject raw bytes + certtype
- generate single annotated CSV report
- generate merge-<timestamp>.sql in current directory for DBA execution
- preserve GBK DN bytes via ATTACH + INSERT OR REPLACE / UPDATE
- compatible with sqlite3 3.6.20 and JDK 1.8
2026-11-04 15:18:42 +08:00

27 KiB
Raw Blame History

HSM 主备数据库证书比对工具 需求文档

项目 内容
文档版本 v0.4
编写日期 2026-11-04
状态 已更新(批量 SQL 方案)
关联文档 设计文档.md
测试环境 172.1.41.139(CentOS 6.5 / JDK 1.8 / SQLite)
测试数据 /app/cert-compare/main.db(4 条)、/app/cert-compare/slave.db(15 条)

1. 背景

HSM 系统使用 SQLite3 数据库保存用户证书,证书保存在 usercert_tab 表中,生产规模约 3000 张。主、备两套系统各自维护一份数据库,长期运行后可能出现:

  • 主库中存在、从库中不存在的证书(主库多);
  • 从库中存在、主库中不存在的证书(从库多);
  • 两边都存在同一张证书(同一 DN + 证书类型),但 SN、有效期、状态等字段不一致;
  • 同一 DN 下存在多张证书(例如双证),不能简单地按 DN 去重。

主备库中的证书都是业务需要的,不存在“多余证书”的概念。比对的目的不是删除数据,而是:

  1. 找出主库多、从库多、字段不一致三类差异;
  2. 由业务人员在报表中逐条确认合并后采用“主”还是“备”;
  3. 以主库为基础,把从库多出的证书补进来,并按人工标注处理冲突,最终形成完整可用的主库数据。

目前依赖人工执行 sqlite3 命令核对,存在以下问题:

  • 表中 subject/issuer 实际存储的是 GBK/GB18030 字节,而 SQLite 头部声明为 UTF-8,直接用 UTF-8 工具读取会出现乱码甚至错误合并;
  • 证书身份不是单纯的 DN,表主键为 (subject, certtype);
  • 3000 条数据人工比对不可行,且容易遗漏;
  • 合并时如果经过 Java String 转换,会破坏原始 GBK 字节,导致写回的数据无法被原系统正确查询。

因此需要一个可在生产环境直接运行的 Java CLI 工具,支持交互式操作和脚本化调用,完成主备库证书比对,并依据人工标注生成在主库执行的批量 SQL 脚本。


2. 建设目标

  1. 通过配置文件同时加载主库、从库两个 SQLite3 数据库。
  2. 以主库为基准,准确识别三类差异:
    • 主库多:仅主库存在;
    • 从库多:仅从库存在;
    • 不一致:两边都有,但比较字段不同。
  3. 提供 set main/slave、compare、sql 等交互命令。
  4. compare 只输出一份报表,包含三类差异;汇总统计直接打印在控制台。
  5. 报表预留“合并选择”字段,人工填写“主”或“备”。
  6. sql 基于人工标注生成在主库上执行的批量 SQL 脚本:
    • 以主库为基准;
    • 从库多的证书全部补入;
    • 不一致的证书按人工标注选择主库版本或从库版本;
    • 脚本由 DBA 在主库执行,工具本身不直接写数据库;
    • 从库仅以 ATTACH 只读引用,DN 中文按原始字节复制。
  7. 不输出日志文件;运行信息、错误信息只打印到控制台。
  8. 兼容生产环境:CentOS 6.5、glibc 2.12、JDK 1.8、无外网、无 Maven。

3. 范围

3.1 本期范围(In Scope)

  • 仅处理 usercert_tab 表;
  • 主库、从库两个数据库路径,以及 SQL 脚本输出目录的配置与切换;
  • 证书比对与三类差异统计;
  • 单份 CSV 报表(含人工合并选择列);
  • 依据报表标注生成批量 SQL 脚本,由 DBA 在主库执行完成合并;
  • 控制台汇总、错误提示、退出码;
  • 交互式 Shell 与一次性命令两种使用方式;
  • 在测试库上完成验收。

3.2 不在本期范围(Out of Scope)

  • HSM 硬件、密钥、私钥的读取或操作;
  • 证书签发、吊销、CRL、信任列表维护;
  • trustlist_tab、apetcert_tab、sym_key 等其他表的合并(SQL 脚本只操作 usercert_tab);
  • 修改现有数据库表结构或索引;
  • Web UI、服务端常驻进程、定时任务;
  • 日志文件、审计日志;
  • 证书密码学有效性验证(签名链、私钥匹配等);
  • 报表中除“主/备”之外的其他合并策略。

4. 术语

术语 说明
主库(main) 基础数据库,合并时以它为基础
从库(slave) 参与比对、提供差异证书的数据库
批量 SQL 脚本 sql 生成的 merge-<时间戳>.sql,由 DBA 在主库执行完成合并
DN / subject 证书主体名称,表中为 C=...,O=...,OU=...,CN=... 形式的自定义顺序字符串,实际为 GBK 字节
SN 证书序列号,表中为十六进制字符串,可能带前导 0,逻辑上唯一
certtype 证书类型,表主键的一部分;同一 DN 可有多张不同 certtype 的证书(如双证)
身份键 判断“同一张证书”的键:subject 原始字节 + certtype
主库多 主库存在、从库不存在的证书
从库多 从库存在、主库不存在的证书
不一致 身份键相同,但 SN、有效期、状态等比较字段不同
一致 身份键相同且比较字段全部相同;只在汇总统计中计数,不进入报表
合并选择 报表中的人工标注列,取值“主”或“备”

5. 用户与使用场景

角色 场景
运维人员 例行核对主备证书差异,导出报表
实施人员 数据迁移、容灾切换后核对并生成批量 SQL 脚本,交 DBA 在主库执行
研发/测试 定位双证、续期、状态差异问题
业务人员 在报表中逐条标注不一致证书采用主库还是从库版本
自动化脚本 执行 compare 生成报表,标注后执行 sql 生成批量脚本

6. 数据规则(已按测试库验证)

6.1 表结构

usercert_tab 主要字段:

字段 类型 说明 比对角色
organid varchar(32) 机构标识 扩展字段
subject varchar(256) DN,GBK/GB18030 字节 身份键、展示字段
issuer varchar(256) 颁发者,GBK/GB18030 字节 默认比较字段
sn varchar(64) 证书序列号,十六进制字符串 唯一编号、默认比较字段
pubkey_alg int 公钥算法 扩展字段
pubkey varchar(1032) 公钥 扩展字段(比较哈希)
sign_alg int 签名算法 扩展字段
signinfo varchar(512) 签名信息 扩展字段(比较哈希)
not_before varchar(14) 生效时间 yyyyMMddHHmmss 默认比较字段
not_after varchar(14) 失效时间 yyyyMMddHHmmss 默认比较字段
certfile varchar(2048) PEM 证书内容 扩展字段(比较哈希)
certtype smallint 证书类型 身份键
opertime varchar(14) 操作时间 扩展字段
stat smallint 状态 默认比较字段

主键:PRIMARY KEY (subject, certtype)。

重要:不能只用 DN 判断同一张证书。测试库中 sge 机构同一 DN 存在 certtype=0 和 certtype=2 两张证书,若按 DN 去重会误判。

6.2 编码规则

  • SQLite PRAGMA encoding 返回 UTF-8,但 subject、issuer 等字段实际写入的是 GBK/GB18030 字节;
  • 使用 JDBC getString() 读取会把非法 UTF-8 字节替换为 U+FFFD,严禁用于比对和回写;
  • 必须通过 hex(col) 或 CAST(col AS BLOB) 获取原始字节;
  • 展示时按 GB18030 解码;解码失败时显示十六进制和转义字符;
  • 合并写入必须使用 SQLite 内部 ATTACH + INSERT ... SELECT,避免 Java 字符串编码转换。

6.3 SN 规则

  • 测试库中 SN 均为十六进制字符串,且与证书 DER 序列号一致;
  • 存在前导 0,例如表中 01971EE53B08,DER 序列号为 1971EE53B08;
  • 比对时默认归一化:去首尾空白、转大写、去前导 0;展示和写回保留原始值;
  • SN 在单个库内逻辑唯一;跨库同 SN 视为同一序列号,但仍以身份键定位证书。

6.4 时间规则

  • not_before、not_after 为 14 位 yyyyMMddHHmmss 本地时间字符串;
  • 测试库全部记录与证书 DER 有效期一致;
  • 比对按原始字符串比较,同时校验格式与 not_before <= not_after;
  • 可选出报告:已过期、未生效、有效,按当前系统时间计算。

6.5 certtype 说明

测试库中观察到 certtype 取值 0/1/2/4/5,同一 DN 可出现多个值。本期不硬编码业务含义,报表按数值展示;后续可通过配置映射为中文名称。


7. 功能需求

FR-01 配置加载

  • 支持 UTF-8 编码的 config.properties;
  • 至少包含:主库路径、从库路径、文本编码、DN 匹配方式、SN 归一化方式、报表目录;
  • 命令行参数优先于配置文件;
  • 配置文件不存在时使用内置默认值,但执行 compare/sql 前必须已有有效配置;
  • 配置错误时给出明确中文提示。

验收:无参数启动进入交互模式;配置中的路径正确显示;路径错误时提示“文件不存在/不可读”,且不覆盖原配置。

FR-02 交互式 Shell

  • 启动后显示 cert-compare> 提示符;
  • 支持命令:set、status、compare、sql、help、quit/exit;
  • 命令大小写不敏感;
  • 支持单引号/双引号包裹含空格的参数;
  • 空行忽略;Ctrl-D 等同于 quit;
  • TERM=dumb 或非 TTY 时不输出 ANSI 颜色控制字符;
  • 单条命令失败不退出 Shell,仅打印错误。

验收:连续执行多条命令,错误后仍可继续;quit 正常退出并返回退出码 0。

FR-03 set main

set main <path>
  • 校验文件存在、可读、是合法 SQLite 文件、包含 usercert_tab 表、必需字段齐全;
  • 成功时输出:绝对路径、文件大小、证书总数;
  • 仅保存路径,不长期持有数据库连接,避免锁库;
  • 无参数执行 set main 时显示当前主库路径与状态。

FR-04 set slave

同 FR-03,用于设置从库路径。

FR-05 SQL 脚本输出位置

  • 不提供单独的输出目录设置命令;
  • sql 生成的脚本直接写入运行时的当前工作目录;
  • 脚本文件名固定为 merge-<yyyyMMdd-HHmmss>.sql,每次生成新文件,不覆盖历史脚本;
  • 启动脚本 cert-compare.sh 会先 cd 到程序目录,因此在服务器上脚本默认落在 /app/cert-compare/。

FR-06 status

显示当前会话状态:

  • 主库、从库的绝对路径、是否存在、文件大小、证书数量;
  • 当前工作目录(即 SQL 脚本输出位置);
  • 当前编码、DN 匹配方式、SN 归一化方式;
  • 主库与从库表结构是否一致;
  • 最近一次 compare 生成的报表路径;
  • 最近一次 sql 生成的脚本路径。

FR-07 compare 分类

对两库全部证书按身份键分类:

分类 判定 是否进入报表
主库多(ONLY_MAIN) 主库有、从库无 是
从库多(ONLY_SLAVE) 从库有、主库无 是
不一致(DIFF) 两边都有,至少一个默认比较字段不同 是
一致(EQUAL) 两边都有,默认比较字段全部相同 否,仅汇总计数

默认比较字段:sn(归一化后)、issuer(原始字节)、not_before、not_after、stat。

compare 不做过滤、不做查询、不接收业务筛选参数;所有差异一次性写入同一份报表,由使用者在报表中自行过滤。

验收:测试库 main.db(4 条)与 slave.db(15 条)比对结果为:一致 0、主库多 1、从库多 12、不一致 3;报表共 16 条差异记录。

FR-08 compare 报表

  • 只生成一份 CSV 报表,不再拆分为多个文件;
  • 文件名:compare-report-<yyyyMMdd-HHmmss>.csv;
  • 控制台只打印汇总统计和报表路径,不打印逐条明细;
  • CSV 使用 UTF-8 + BOM,保证 Excel 打开中文不乱码;
  • 报表只包含主库多、从库多、不一致三类记录,不包含一致记录;
  • 报表至少包含以下列:
列 说明
序号 报表内序号,便于人工沟通
类型 主库多 / 从库多 / 不一致
DN GB18030 解码后的 DN,便于阅读
DN_HEX 原始 DN 字节十六进制,带 HEX: 前缀,用于精确匹配
CN 从 DN 提取的 CN,仅展示
CERTTYPE 证书类型
主库SN / 从库SN 两边 SN,不存在的一侧留空
主库生效 / 主库失效 主库有效期,不存在的一侧留空
从库生效 / 从库失效 从库有效期,不存在的一侧留空
主库状态 / 从库状态 两边 stat,不存在的一侧留空
差异字段 不一致时列出差异字段,如 sn;not_after
合并选择 最后一列,人工填写:主 / 备
  • 合并选择 固定放在最后一列,便于 Excel 中直接拉到最右侧填写;
  • 报表不再包含“备注”列,数据异常信息改由 compare 在控制台“提示”中输出;
  • DN_HEX 统一加 HEX: 前缀,避免 Excel 把长十六进制转换成科学计数法;sql 读取时自动去掉前缀;
  • 默认不输出 certfile、pubkey、signinfo 等大字段;
  • 报表生成后,控制台打印报表绝对路径和汇总统计。

FR-09 人工标注规则

  • 主库多:只有主库记录,合并选择 默认填 主,且只允许 主;
  • 从库多:只有从库记录,合并选择 默认填 备,且只允许 备;
  • 不一致:合并选择 默认留空,必须人工填写 主 或 备;
  • 空白或非法值(非“主/备”)在 sql 时视为错误,拒绝生成脚本并提示具体行号;
  • 人工只能修改 合并选择 列,不应修改 DN、DN_HEX、CERTTYPE 等定位列;
  • 报表保存为 UTF-8 或 GBK/GB18030 均可,sql 读取时自动识别。

FR-10 sql 生成计划

sql 读取已人工标注的报表,校验后生成批量 SQL 脚本,并先打印计划:

  • 主库证书数、从库证书数;
  • 一致、主库多、从库多、不一致数量;
  • 写入记录数(从库多 + 不一致选备);
  • 不一致中选择“主”的数量、选择“备”的数量;
  • 执行后主库应有的记录数;
  • 从库路径(脚本以 ATTACH 只读引用)与脚本输出路径;
  • 控制台给出“备份主库 + sqlite3 主库 < 脚本”的执行命令。

sql 只写脚本文件,不连接主库执行、不修改任何数据库。

FR-11 批量 SQL 脚本内容

  • 脚本输出到运行时的当前工作目录,文件名 merge-<yyyyMMdd-HHmmss>.sql;
  • 脚本本身不携带证书数据,而是 ATTACH DATABASE '<从库>' AS cert_src 后按身份键复制;
  • 从库多的证书:INSERT OR REPLACE ... SELECT ... FROM cert_src.usercert_tab WHERE ...;
  • 不一致 + 选择主:不产生语句,主库版本自然保留;
  • 不一致 + 选择备:用从库版本整行替换主库版本;
  • 主库多:不产生语句,主库版本自然保留;
  • 所有语句按身份键(hex(subject) + certtype)定位,不出现 DN 文本,从库记录由 SQLite 内部按原始字节复制,DN 中的 GBK 中文不会被解码或重新编码;
  • 脚本使用 BEGIN IMMEDIATE / COMMIT 包裹,可重复执行且结果一致(幂等);
  • 脚本末尾输出 select 'rows', count(*) 与 PRAGMA integrity_check 供执行后自检;
  • 脚本为 UTF-8(无 BOM),SQL 语句与字符串字面量全部为 ASCII,仅注释包含中文。

FR-12 sql 报表校验

生成脚本前必须校验:

  1. 报表存在、可解析、列头完整;
  2. 报表中的差异记录与当前两库重新比对的结果一致(差异数量、身份键、类型);报表中的 SN/有效期等字段仅供人工阅读,脚本数据始终取自当前数据库;
  3. 每条记录都有合法的“合并选择”;
  4. 报表中的差异键集合、类型与当前比对一致;差异集合发生变化时视为报表过期,必须重新 compare。

校验失败时拒绝生成脚本,提示“报表已过期或标注不完整,请重新执行 compare 并标注”,不产生任何脚本。

FR-13 脚本执行与结果校验

脚本由 DBA 在主库上执行:

cp -p /app/cert-compare/main.db /app/cert-compare/main.db.bak-$(date +%Y%m%d-%H%M%S)
sqlite3 /app/cert-compare/main.db < /app/cert-compare/merge-20261104-213307.sql

执行后应满足:

  1. 脚本输出 rows 等于“主库数量 + 从库多数量”;
  2. PRAGMA integrity_check 返回 ok;
  3. 选择“主”的不一致记录保持主库版本;
  4. 选择“备”的不一致记录等于从库版本;
  5. 从库多记录全部存在,DN/SN/时间等字段与从库一致;
  6. 从库文件不被修改(脚本只读引用);
  7. 主库 DN 中文按原始字节写入,hex(subject) 与来源库一致。

FR-14 错误与退出码

  • 不生成任何日志文件;
  • 运行信息、警告、错误只输出到控制台;
  • --debug 时可在控制台输出详细堆栈;
  • 退出码:
退出码 含义
0 成功(交互模式正常退出)
1 未预期内部错误
2 参数/配置错误
4 数据库打开失败、表结构不兼容、完整性校验失败
5 报表过期、标注非法、SQL 脚本生成/写入失败

FR-15 一次性命令模式

支持不进入交互 Shell,直接执行:

# 生成报表
java -Dfile.encoding=UTF-8 -jar cert-compare.jar compare \
  --config /app/cert-compare/config.properties

# 人工标注报表后生成批量 SQL
java -Dfile.encoding=UTF-8 -jar cert-compare.jar sql \
  --config /app/cert-compare/config.properties \
  --report /app/cert-compare/reports/compare-report-20261104-213307-annotated.csv

# 由 DBA 在主库执行生成的脚本
sqlite3 /app/cert-compare/main.db < /app/cert-compare/merge-20261104-213307.sql

一次性模式与交互模式共用同一套比对、报表、SQL 生成引擎,结果必须一致。

FR-16 help

  • help 输出命令列表与示例;
  • help compare、help sql 输出用法说明;
  • 未知命令给出提示,不退出 Shell。

8. 非功能需求

编号 需求
NFR-01 兼容性 可在 CentOS 6.5 / glibc 2.12 / JDK 1.8 上运行;无外网依赖;不要求服务器安装 Maven
NFR-02 性能 3000 张证书:compare ≤ 3 秒,sql ≤ 3 秒;生成的脚本可在 sqlite3 3.6.20 上执行;JVM 内存 ≤ 256MB
NFR-03 编码正确性 DN/issuer 原始字节零损失;合并前后十六进制一致;脚本中不出现 DN 文本;禁止 U+FFFD 参与比较
NFR-04 数据安全 工具默认只读源库;不直接修改任何数据库,只生成 SQL 脚本;不生成日志文件
NFR-05 可靠性 脚本使用事务包裹且可重复执行;执行失败可按备份回滚;从库 SHA-256 不变
NFR-06 易用性 中文提示;报表可直接用 Excel 标注;错误信息包含原因与处理建议
NFR-07 可维护性 分层设计;核心逻辑有单元测试;不修改现有表结构
NFR-08 可部署性 单个可执行 fat jar + 配置文件 + 启动脚本即可部署
NFR-09 报表兼容性 报表读取兼容 UTF-8 BOM、UTF-8、GBK/GB18030 三种保存方式

9. 交互与输出示例

9.1 设置数据库

cert-compare> set main /app/cert-compare/main.db
[OK] 主库: /app/cert-compare/main.db (459,776 字节, 4 张证书)

cert-compare> set slave /app/cert-compare/slave.db
[OK] 从库: /app/cert-compare/slave.db (459,776 字节, 15 张证书)

9.2 比对

cert-compare> compare

主库: /app/cert-compare/main.db    证书数: 4
从库: /app/cert-compare/slave.db   证书数: 15

汇总:
  一致        0
  主库多      1
  从库多     12
  不一致      3
  差异合计   16

报表:
  /app/cert-compare/reports/compare-report-20261103-205500.csv

请按“合并选择”列标注:主 或 备,然后执行 sql 生成批量脚本。

9.3 报表示例(CSV)

序号,类型,DN,DN_HEX,CN,CERTTYPE,主库SN,从库SN,主库生效,主库失效,从库生效,从库失效,主库状态,从库状态,差异字段,合并选择
1,从库多,"C=CN,ST=北京,L=北京,O=信雅达,OU=双证,CN=172.1.40.188","HEX:433D434E2C...",172.1.40.188,0,,01971EE53B08,,,20250529160000,20260529160000,,0,,备
2,主库多,"C=cn,O=CFCA OCA1 SM2,OU=Local RA OCA1,OU=Business Customers,CN=041@...@陈超@...","HEX:433D636E2C...",041@...@陈超@...,1,1177482454,,20260806025132,20270806025132,,,,0,,主
14,不一致,CN=diff-sn-01,"HEX:434E3D646966662D736E2D3031",diff-sn-01,0,0A0B0C01,0A0B0C11,20260101000000,20301231235959,20260101000000,20301231235959,0,0,sn,主
15,不一致,CN=diff-stat-03,"HEX:434E3D646966662D737461742D3033",diff-stat-03,5,0A0B0C03,0A0B0C03,20260101000000,20301231235959,20260101000000,20301231235959,0,1,stat,主
16,不一致,CN=diff-time-02,"HEX:434E3D646966662D74696D652D3032",diff-time-02,2,0A0B0C02,0A0B0C02,20260101000000,20301231235959,20260101000000,20311231235959,0,0,not_after,备

9.4 生成批量 SQL

cert-compare> sql --report /app/cert-compare/reports/compare-report-20261104-213307-annotated.csv

SQL 生成计划:
  主库证书数                4
  从库证书数               15
  一致                   0
  主库多                  1
  从库多                 12
  不一致                  3
  写入(从库多+选备)           13
  不一致选主                2
  不一致选备                1
  执行后主库记录数             16
  从库(只读引用)             /app/cert-compare/slave.db
  SQL 文件               /app/cert-compare/merge-20261104-213307.sql

请在主库上执行(执行前先备份):
  cp -p /app/cert-compare/main.db /app/cert-compare/main.db.bak-$(date +%Y%m%d-%H%M%S)
  sqlite3 /app/cert-compare/main.db < /app/cert-compare/merge-20261104-213307.sql

执行后主库记录数应为 16 条;脚本末尾会输出 rows 与 integrity_check 结果。

执行脚本后:

rows|16
ok

10. 验收标准

编号 场景 期望结果
AC-01 set main/slave 路径正确显示;主库 4 条、从库 15 条;当前目录可写
AC-02 compare 一致 0、主库多 1、从库多 12、不一致 3;控制台只打印汇总
AC-03 报表 只生成一份 CSV,含 16 条差异记录;“合并选择”为最后一列,无“备注”列
AC-04 默认标注 主库多默认“主”,从库多默认“备”,不一致留空
AC-05 标注后 sql 生成 1 个 SQL 脚本;1 条 INSERT OR REPLACE(13 个身份键);无 UPDATE 语句
AC-06 不一致选主 执行脚本后该身份键字段与主库一致
AC-07 不一致选备 执行脚本后该身份键字段与从库一致
AC-08 报表编码 UTF-8 BOM 报表 Excel 打开中文正常;GBK 保存后 sql 仍可读取
AC-09 报表过期 数据库变化后使用旧报表生成脚本,拒绝执行并提示重新 compare
AC-10 标注非法 不一致记录留空或填“其他”,生成脚本被拒绝并提示行号
AC-11 同一 DN 不同 certtype sge 的 certtype=0 与 2 均保留,不互相覆盖
AC-12 字节保持 执行脚本后每条 hex(subject) 与来源库一致,typeof(subject)='text'
AC-13 源库只读 生成脚本前后两源文件 SHA-256 不变;执行后从库 SHA-256 不变
AC-14 无日志文件 运行过程不生成 *.log,信息仅输出到控制台
AC-15 3000 条模拟数据 compare ≤ 3s,sql ≤ 3s,内存 ≤ 256MB
AC-16 脚本兼容性 脚本可在服务器 sqlite3 3.6.20 上一次执行成功,重复执行结果一致

11. 假设、约束与待确认事项

11.1 已确认

  • set main / set slave 设置主库、从库路径;
  • sql 生成的脚本直接写入运行时的当前工作目录;
  • sql 只生成脚本,不直接修改任何数据库;脚本由 DBA 在主库执行;
  • 脚本通过 ATTACH 从从库按原始字节复制,DN 中文不经过字符集转换;
  • 证书身份键为 DN + certtype,SN 作为唯一编号参与比较;
  • 主库多、从库多、不一致三类差异均进入同一份报表;
  • 合并选择只有“主”“备”两种;
  • 不生成日志文件。

11.2 假设

  • usercert_tab 结构在生产与测试环境一致;
  • 证书数量约 3000,单库文件规模在数十 MB 以内;
  • 生产比对可在业务低峰或维护窗口执行,避免与 HSM 应用并发写冲突;
  • 服务器 /tmp 可写且允许执行(sqlite-jdbc 需解压本地库);
  • 业务人员使用 Excel 或文本编辑器修改报表的“合并选择”列。

11.3 待确认

  1. certtype 各数值的业务含义(0/1/2/4/5),是否需要报表中文映射;
  2. 生产环境是否允许停应用/只读挂载,或必须在线比对;
  3. 是否需要同时核对 trustlist_tab、apetcert_tab(本期不做);
  4. SQL 脚本文件命名与保留策略(当前为 merge-<时间戳>.sql,不覆盖历史脚本);
  5. SN 前导 0 归一化是否与现网查询逻辑一致;
  6. DN 是否需要忽略属性大小写/顺序的“近似匹配”(本期默认严格字节匹配);
  7. 主库多/从库多的“合并选择”是否允许改成其他值(本期固定为主/备,确保不丢证书)。

12. 里程碑

阶段 内容 交付物
M1 环境验证、需求与设计 本文件、设计文档.md
M2 工程骨架、配置、set/status 可启动的 CLI、配置加载、库校验
M3 compare 引擎与单份报表 三类差异、控制台汇总、CSV
M4 报表读取、标注校验、批量 SQL 生成 SQL 脚本、脚本执行验证
M5 测试与部署 单元/集成测试、3000 条压测、部署脚本、验收记录

13. 附:测试库现状摘要

项目 main.db slave.db
文件大小 459,776 字节 459,776 字节
usercert_tab 记录数 4 15
certtype 分布 0:1、1:1、2:1、5:1 0:5、2:3、4:1、5:6
重复身份键 无 无
同一 DN 多证书 无 有(sge,certtype 0/2)
重复 SN 无 无
日期格式异常 无 无
完整性检查 ok ok

其中 3 条为专门构造的“不一致”测试数据(主备同 DN + certtype,SN/有效期/状态不同):

DN CERTTYPE 差异 主库 从库
CN=diff-sn-01 0 SN 0A0B0C01 0A0B0C11
CN=diff-time-02 2 失效时间 20301231235959 20311231235959
CN=diff-stat-03 5 状态 0 1

按本期规则,测试库的预期比对结论为:

  • 主库多:1 张;
  • 从库多:12 张;
  • 不一致:3 张;
  • 一致:0 张;
  • 报表差异记录:16 条;
  • 执行 SQL 后(示例标注:2 条选主、1 条选备):16 张。