Files
hsm-database-certs-compare/README.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

5.4 KiB
Raw Blame History

HSM 主备数据库证书比对工具

Java 8 命令行工具,用于比对 HSM 主库、从库 SQLite 数据库中的 usercert_tab,生成一份差异报表,并按人工标注的“合并选择”生成在主库执行的批量 SQL 脚本。

  • 身份键:subject 原始字节 + certtype
  • 三类差异:主库多、从库多、不一致
  • 报表:单份 CSV(UTF-8 + BOM),含“合并选择”列
  • 合并方式:生成 merge-<时间戳>.sql,由 DBA 在主库执行
  • 工具本身只读源库,不直接修改任何数据库
  • 脚本通过 ATTACH 从从库按原始字节复制,DN 中文(GBK 字节)不经过 Java 字符串
  • 不生成日志文件,信息只输出到控制台

详细需求与设计见 需求文档.md、设计文档.md。

构建

要求:JDK 8 + Maven 3.x。

mvn clean package
# 产物:target/cert-compare.jar(fat jar,含 sqlite-jdbc 原生库)

当前构建:12 个单元测试全部通过,jar 约 9.8 MB。

配置

config.properties(UTF-8):

db.main=/app/cert-compare/main.db
db.slave=/app/cert-compare/slave.db
db.text.encoding=GB18030
dn.match=EXACT
sn.normalize=HEX
report.dir=/app/cert-compare/reports
report.csv.bom=true

相对路径以配置文件所在目录为基准。SQL 脚本不配置输出目录,直接写入运行时当前目录。

使用

交互模式

java -Dfile.encoding=UTF-8 -jar cert-compare.jar --config config.properties
cert-compare> set main /app/cert-compare/main.db
cert-compare> set slave /app/cert-compare/slave.db
cert-compare> compare
cert-compare> sql --report /app/cert-compare/reports/compare-report-20261104-213307-annotated.csv

一次性命令

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

# 2. 人工标注“合并选择”后生成批量 SQL
java -Dfile.encoding=UTF-8 -jar cert-compare.jar sql \
  --config config.properties \
  --report /app/cert-compare/reports/compare-report-20261104-213307-annotated.csv

# 3. 由 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

sql 只生成脚本,不写数据库、不需要确认参数;脚本直接写入运行时的当前目录。

合并选择规则

类型 默认值 允许值
主库多 主 仅主
从库多 备 仅备
不一致 空 主 / 备

sql 生成前会重新比对并校验报表是否过期、标注是否完整;不合法时拒绝生成脚本并提示行号(退出码 5)。

报表

文件名:compare-report-yyyyMMdd-HHmmss.csv。

列为:序号,类型,DN,DN_HEX,CN,CERTTYPE,主库SN,从库SN,主库生效,主库失效,从库生效,从库失效,主库状态,从库状态,差异字段,合并选择。

  • 合并选择 放在最后一列,方便直接填写“主”或“备”。
  • 报表不含“备注”列;日期非法、SN/DN 为空等异常在 compare 控制台“提示”中输出。
  • DN_HEX 带 HEX: 前缀,避免 Excel 把长十六进制转为科学计数法。
  • 报表可用 Excel 直接编辑,另存为 UTF-8 CSV 或 GBK CSV 均可读取。
  • sql 只信任“合并选择”列,证书数据始终取自当前数据库。

生成的 SQL 脚本

  • 文件名:merge-yyyyMMdd-HHmmss.sql,写入运行时当前目录,不覆盖历史脚本。
  • ATTACH DATABASE '<从库>' AS cert_src,按 hex(subject) + certtype 定位。
  • 从库多、不一致选备:INSERT OR REPLACE ... SELECT(整行复制)。
  • dn.match=TRIM 且主备 DN 字节不同时:UPDATE ... SET col = (SELECT ...),按主库字节定位。
  • 主库多、不一致选主:不产生语句。
  • 使用 BEGIN IMMEDIATE / COMMIT 包裹,可重复执行(幂等)。
  • 末尾输出 SELECT 'rows' 与 PRAGMA integrity_check 供执行后自检。
  • 脚本为 UTF-8 无 BOM,SQL 与字符串字面量全 ASCII,DN 只以十六进制出现。
  • 兼容服务器 sqlite3 3.6.20。

测试数据

scripts/test-data-main.sql 与 scripts/test-data-slave.sql 会在原测试库中增加 3 组“不一致”数据:

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

执行前请备份:

cp -p main.db main.db.bak-$(date +%Y%m%d-%H%M%S)
cp -p slave.db slave.db.bak-$(date +%Y%m%d-%H%M%S)
sqlite3 main.db < scripts/test-data-main.sql
sqlite3 slave.db < scripts/test-data-slave.sql

当前测试库预期结果:

主库 4 条,从库 15 条
一致 0、主库多 1、从库多 12、不一致 3
报表 16 条
执行脚本后主库 16 条(2 条选主、1 条选备)

部署

scp target/cert-compare.jar root@172.1.41.139:/app/cert-compare/
scp config.properties root@172.1.41.139:/app/cert-compare/
scp scripts/cert-compare.sh root@172.1.41.139:/app/cert-compare/
ssh root@172.1.41.139
cd /app/cert-compare
chmod +x cert-compare.sh
./cert-compare.sh

cert-compare.sh 已设置 -Dfile.encoding=UTF-8 -Xmx256m。

退出码

码 含义
0 成功
1 未预期内部错误
2 参数/配置错误
4 数据库/结构/完整性错误
5 报表过期、标注非法、SQL 脚本生成/写入失败