- 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
27 KiB
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 去重。
主备库中的证书都是业务需要的,不存在“多余证书”的概念。比对的目的不是删除数据,而是:
- 找出主库多、从库多、字段不一致三类差异;
- 由业务人员在报表中逐条确认合并后采用“主”还是“备”;
- 以主库为基础,把从库多出的证书补进来,并按人工标注处理冲突,最终形成完整可用的主库数据。
目前依赖人工执行 sqlite3 命令核对,存在以下问题:
- 表中
subject/issuer实际存储的是 GBK/GB18030 字节,而 SQLite 头部声明为 UTF-8,直接用 UTF-8 工具读取会出现乱码甚至错误合并; - 证书身份不是单纯的 DN,表主键为
(subject, certtype); - 3000 条数据人工比对不可行,且容易遗漏;
- 合并时如果经过 Java
String转换,会破坏原始 GBK 字节,导致写回的数据无法被原系统正确查询。
因此需要一个可在生产环境直接运行的 Java CLI 工具,支持交互式操作和脚本化调用,完成主备库证书比对,并依据人工标注生成在主库执行的批量 SQL 脚本。
2. 建设目标
- 通过配置文件同时加载主库、从库两个 SQLite3 数据库。
- 以主库为基准,准确识别三类差异:
- 主库多:仅主库存在;
- 从库多:仅从库存在;
- 不一致:两边都有,但比较字段不同。
- 提供
set main/slave、compare、sql等交互命令。 compare只输出一份报表,包含三类差异;汇总统计直接打印在控制台。- 报表预留“合并选择”字段,人工填写“主”或“备”。
sql基于人工标注生成在主库上执行的批量 SQL 脚本:- 以主库为基准;
- 从库多的证书全部补入;
- 不一致的证书按人工标注选择主库版本或从库版本;
- 脚本由 DBA 在主库执行,工具本身不直接写数据库;
- 从库仅以
ATTACH只读引用,DN 中文按原始字节复制。
- 不输出日志文件;运行信息、错误信息只打印到控制台。
- 兼容生产环境: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 报表校验
生成脚本前必须校验:
- 报表存在、可解析、列头完整;
- 报表中的差异记录与当前两库重新比对的结果一致(差异数量、身份键、类型);报表中的 SN/有效期等字段仅供人工阅读,脚本数据始终取自当前数据库;
- 每条记录都有合法的“合并选择”;
- 报表中的差异键集合、类型与当前比对一致;差异集合发生变化时视为报表过期,必须重新
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
执行后应满足:
- 脚本输出
rows等于“主库数量 + 从库多数量”; PRAGMA integrity_check返回ok;- 选择“主”的不一致记录保持主库版本;
- 选择“备”的不一致记录等于从库版本;
- 从库多记录全部存在,DN/SN/时间等字段与从库一致;
- 从库文件不被修改(脚本只读引用);
- 主库 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 待确认
certtype各数值的业务含义(0/1/2/4/5),是否需要报表中文映射;- 生产环境是否允许停应用/只读挂载,或必须在线比对;
- 是否需要同时核对
trustlist_tab、apetcert_tab(本期不做); - SQL 脚本文件命名与保留策略(当前为
merge-<时间戳>.sql,不覆盖历史脚本); - SN 前导 0 归一化是否与现网查询逻辑一致;
- DN 是否需要忽略属性大小写/顺序的“近似匹配”(本期默认严格字节匹配);
- 主库多/从库多的“合并选择”是否允许改成其他值(本期固定为主/备,确保不丢证书)。
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 张。