OnecardDemo 用户信息 SQLite 分批持久化设计

日期:2026-08-24
状态:已实施,待现场全量同步验证

1. 目标与已确认规则

“获取全部用户信息”继续按每批最多 1000 条调用 GetCustomerByNum,但不再把全部 SOAP XML 留在内存并显示到页面。每个请求成功并完成解析后,立即在单独事务中写入应用私有 SQLite 数据库。

已确认的业务规则:

2. 真实响应结构证据

2026-08-24 使用现场 WebService、AppID 6 调用 GetCustomerByNum(custid=0, num=2),只检查 XML 结构和字段名,不记录字段值。响应包含 2 个 PROXY_BASE_CUSTOMERS 用户节点,每个节点当前包含 51 个字段:

CUSTOMERIDOUTIDSCARDSNRCARDNOCARDSNBANKCARDNOSTATUSOPENDTNOUSEDATEPWDOPCOUNTCARDFUNCCARDTYPECARDSFIDCUSTDEPTEMPCODESUMFAREODDFARESUBODDFAREODDFAREACCSUBODDFAREACCSUMCONSUMEFARESUMADDFARESUMSUBSIDYSUMQCSUMLOADSUMSAVESUMSXFIFPUSHFARENAMEJPDMSEXCERTIFICATEIDIDCARDNOSERVERIDMEDICALTYPEREGSTARTYEARVERQUERYPWDPHOTOIDISBIGFARECARDCOUNTRYNATIONSUBOPCOUNTSUBSAVEOPCOUNTSPECIALOPCOUNTSAVEOPCOUNTSPECIALODDFARECARDKINDCARDOPERTYPECardBlock

字段集合可能随服务端版本变化,因此数据库不能只建立固定的 51 个业务列。

3. 数据库结构

数据库文件为应用私有目录中的 onecard.db,数据库版本从 1 开始,使用 Android 系统 SQLiteOpenHelper,不增加 Room 或第三方数据库依赖。

3.1 用户主表 customers

字段 类型 规则
customer_id INTEGER 主键,对应原始 CUSTOMERID
card_no TEXT 原始 CARDNO,建立普通索引
out_id TEXT 原始 OUTID,建立普通索引
name TEXT 原始 NAME
status TEXT 原始 STATUS
last_seen_sync_id TEXT 最后一次看到该用户的同步批次 ID
updated_at INTEGER 本机保存时的毫秒值

主表保存后续业务最常用的查询字段,所有值保持服务端原始字符串;除了 customer_id 用于唯一性外,不对金额、日期、状态进行业务转换。

3.2 原始字段表 customer_fields

字段 类型 规则
customer_id INTEGER 关联 customers.customer_id
field_name TEXT 服务端 XML 原始元素名,按原样保存
field_value TEXT 服务端原始文本值,允许空字符串

联合主键为 (customer_id, field_name)。每次更新一个用户时,先删除该用户的旧字段,再写入本次响应中的全部字段,确保被服务端删除的字段不会残留。外键级联删除。

3.3 同步记录表 customer_sync_runs

字段 类型 规则
sync_id TEXT 主键,使用开始时间毫秒和进程内序号生成
started_at / completed_at INTEGER 同步开始/结束毫秒值
expected_count INTEGER GetCustomerCount 返回数量
saved_count INTEGER 本轮累计成功保存数量
successful_batches INTEGER 已提交的成功批次数
status TEXT RUNNINGSUCCESSFAILED
error_message TEXT 失败原因;成功时为空

4. 每批保存流程

  1. 创建同步记录并调用 GetCustomerCount
  2. 使用当前分页常量请求一批 GetCustomerByNum
  3. 从每个 PROXY_BASE_CUSTOMERS 节点读取全部直接子元素,形成 CustomerRecord(customerId, fields)
  4. 如果某条记录缺少合法 CUSTOMERID、同一节点存在重复字段名、本批出现重复 CUSTOMERID 或本批没有任何用户,则整批解析失败,不写入数据库。
  5. 开启 SQLite 事务,对本批每个 CUSTOMERID 执行主表 upsert、原始字段替换和 last_seen_sync_id 更新,同时更新同步进度。
  6. 事务提交后才开始下一批;提交失败时整批回滚,之前已提交批次不受影响。
  7. 下一批仍从当前批最大 CUSTOMERID + 1 开始,剩余数量按实际保存条数递减。
  8. 全部批次成功后,在事务内删除 last_seen_sync_id != 当前 sync_id 的旧用户,并把同步记录标记为 SUCCESS
  9. 任一后续请求、解析或保存失败时,把同步记录标记为 FAILED,保留之前成功批次,不执行旧用户清理。

5. 代码边界

6. 安全边界

由于数据库包含密码摘要和证件号:

7. 验证与验收

8. 非目标