发明专利技术交底书
1. 发明名称
一种工业级本地 SQLite 私有数据存储的双层隔离与跨后端适配方法
2. 技术领域
本发明涉及工业软件数据持久化与私有化存储技术领域,具体涉及一种面向产品生命周期管理(PLM)、企业资源规划(ERP)等工业系统的本地 SQLite 私有数据存储方法,尤其涉及一种将云端工业数据库以"读写分流"方式镜像为本地私有库、实现多租户物理隔离、跨 SQLite/MySQL 后端零改动适配及损坏自愈的方法及其系统。
3. 背景技术
在离散/流程制造企业的数字化系统中,业务数据(对象、规则、文档、资产)通常存放于中心化的云端数据库(如 SCSAI MSSQL、MySQL 集群)。传统持久化方案存在以下突出缺陷:
(1)直连云数据库:所有读写均经网络访问中心库,存在"数据出域"的合规风险,且离线、弱网、中心库宕机时业务完全不可用;查询流量受网络与权限约束,响应慢。
(2)纯本地文件库:虽解决了私有化与离线可用,但缺乏权威数据源,多端写入易产生脏数据、版本不一致,无法与中心系统协同。
(3)逻辑多租户隔离:传统方案在"同一库 + tenant_id 列"上做逻辑隔离,越权访问面大,且一个租户的慢查询或锁会影响其他租户;缺少独立的跨租户访问控制与配额。
(4)SQLite 与 MySQL 难以互切:工业系统常在"边缘/私有化部署用 SQLite、中心化部署用 MySQL"间切换,但两套数据库 SQL 方言、异步/同步模型不同,业务代码需大量改写。
(5)内存多副本与损坏即中断:旧版 SQLite 封装常出现同一文件在内存中存在多个副本相互覆盖,导致静默数据丢失;数据库文件一旦损坏(malformed),服务直接无法启动。
因此,亟需一种既能保证数据私有化与离线可用、又能与云端权威源协同,且可安全隔离多租户、跨后端零改动切换、并能从损坏中自愈的工业级本地存储方法。
4. 发明内容
4.1 要解决的技术问题
- 解决工业数据"私有化/不出域"与"与云端权威源一致"难以兼得的问题,提供读写分流的双层镜像边界;
- 解决多租户隔离不彻底、越权面大的问题,提供单文件级物理隔离与请求链路越权拦截;
- 解决 SQLite 与 MySQL 后端切换需大量改代码的问题,提供同一套同步 API 屏蔽两种后端的差异;
- 解决内存多副本覆盖致静默丢失、数据库损坏致服务中断的问题,提供单例规范化与损坏自愈。
4.2 技术方案
本发明提供一种工业级本地 SQLite 私有数据存储的双层隔离与跨后端适配方法,由本地私有镜像层、多租户隔离层、跨后端适配层与损坏自愈层协同实现。下面对应真实代码(位于 server/utils/、server/shared/、server/ 根目录与 server/middleware/)描述关键构成。
(一)双库分层与读写分流的私有化边界
PrivateStore(server/utils/private-store.js)以 enterprise_store.db 作为云端 SCSAI MSSQL 的本地镜像:所有"查/浏览/搜索"走本地 SQLite,所有"增/改/删"仍走云端 SCSAI API 并在完成后同步回本库(private-store.js:1-46 注释明确该边界)。server/routes/private-library.js 的 POST /api/private-library/sync/:type 提供从 SCSAI 拉取的同步入口。由此既保证企业数据"查询不出本地域、离线可用",又不牺牲工业数据一致性。
(二)多租户物理隔离与越权拦截
server/tenant-db.js 采用"一个客户 = 一个 SQLite 文件"的物理隔离:tenantDbPath(customerId) 将库置于 data/tenants/,sanitize(id) 以白名单 [^a-zA-Z0-9_-] 截断 64 字符防止路径穿越,getTenantDb() 用 Map 缓存每租户实例;默认租户复用历史 bossagents.db 兼容旧数据。server/middleware/tenant-middleware.js 在请求链路加固:tenantInject 注入 req.tenantContext;tenantDataGuard 当请求体 enterprise_id 与上下文不符时拒绝跨租户访问并返回 403 并写审计;quotaGuard 做配额校验;SCSAIQueryFilter 向云端 AML 查询注入 标签,使云查询也按企业隔离。
(三)跨后端统一适配与同步 API 伪装
server/db-adapter.js 的 getBackend() 依据 DB_BACKEND/DB_TYPE 判定 sqlite|mysql;init() 在 MySQL 初始化失败时自动回退 SQLite,createDatabase() 在 MySQL 未就绪时临时用 SQLite 待切换。nowExpr()/autoIncrementPK()/textPK() 返回后端相关 SQL 片段,调用方无需感知差异。关键创新在 server/mysql-compat.js:MySQL 本为异步,但用 Worker Thread + SharedArrayBuffer + Atomics.wait/notify 把异步查询"伪装"为同步阻塞调用(_syncRequest),使上层业务代码在 SQLite 与 MySQL 下无需改动一行;convertSQL() 系统地把 SQLite 方言翻译为 MySQL(datetime('now')→NOW()、INTEGER PRIMARY KEY AUTOINCREMENT→INT AUTO_INCREMENT PRIMARY KEY、TEXT PRIMARY KEY→VARCHAR(255)、INSERT OR REPLACE→REPLACE、sqlite_master→information_schema.tables 等 12 类);并把 ER_DUP_ENTRY 等错误静默为 {changes:0} 以对齐 SQLite 的 OR IGNORE 语义。
(四)损坏自愈与单例防覆盖
server/sqlite-compat.js 在 _openCanonical 时执行 _setPragma(db,'journal_mode = WAL') 并开启 foreign_keys=ON;打开即探活(SELECT count(*) FROM sqlite_master),命中 malformed database schema 时调用 _backupCorrupt() 将损坏库连同 -wal/-shm 重命名为 .corrupt-<时间戳> 留存再建新库,保证服务可启动。_instances 按 canonicalPath 规范化绝对路径缓存单例,从架构上消除"同文件多内存副本互相覆盖"缺陷;prepare/exec 失败直接抛出含 SQL 片段的错误(FAILFAST),取代旧版静默空 catch。
4.3 有益效果
- 私有化与一致性兼得:读写分流使查询不出域、离线可用,写仍以云端为权威,避免纯本地库的脏数据;
- 隔离更彻底:单文件级物理隔离 + 链路层 403 越权拦截与配额,越权面远小于逻辑隔离;
- 零改动跨后端迁移:同步 API 伪装 + 12 类方言转换,业务代码可在嵌入式 SQLite(边缘)与集群 MySQL(中心)间无缝切换;
- 自愈与防丢失:损坏即备份留存 + 自动建新库,单例规范化根治多副本覆盖,服务可用性显著提升。
5. 附图说明
图1 系统架构图:展示本地私有镜像层(private-store)、多租户隔离层(tenant-db+tenant-middleware)、跨后端适配层(db-adapter+sqlite-compat+mysql-compat)、云端权威源(SCSAI/MySQL)及同步桥接(sync-service)的分层关系。
图2 读写分流时序图:描述一次查询请求走本地 SQLite 镜像、一次写入请求走云端 SCSAI 并回写本地库的流程。
图3 多租户隔离图:展示 sanitize→tenantDbPath→单文件库 + tenantDataGuard 的 403 拦截。
图4 跨后端切换图:展示 _syncRequest 将异步 MySQL 同步化、convertSQL 方言转换使上层业务代码零改动。
6. 具体实施方式
步骤一:私有镜像初始化与读写分流。 系统启动加载 private-store.js,以 DB_PATH='data/enterprise_store.db' 建立镜像库并建 enterprise_objects 表;读操作(save/get/list/search/exactMatch/json_extract 精确匹配、Jaccard 模糊匹配)仅访问本地库,写操作经 SCSAI API 完成后由 sync 回写。
步骤二:多租户物理隔离。 请求进入 tenant-middleware,sanitize 过滤租户 ID,经 tenantDbPath 定位 data/tenants/;getTenantDb 取缓存实例;tenantDataGuard 校验 enterprise_id 一致,否则返回 403 并审计。
步骤三:跨后端适配(同步 API 伪装)。 业务代码统一调用 createDatabase/prepare().run/all/get/exec/transaction;后端为 MySQL 时,mysql-compat._syncRequest 经 Worker + Atomics 阻塞等待结果,convertSQL 将方言透明转换,错误语义对齐 SQLite:
function _syncRequest(type, sql, params, sqlList) {
const reqId = ++_requestId;
Atomics.store(_lock, LOCK_OFFSET, 0);
_worker.postMessage({ id: reqId, type, sql, params, sqlList });
const waitResult = Atomics.wait(_lock, LOCK_OFFSET, 0, 30000); // 主线程阻塞等待 Worker
if (waitResult === 'timed-out') throw new Error('MySQL 查询超时 (30s)');
const resp = _readResponse();
if (!resp.ok) { const err = new Error(resp.error); err.code = resp.code; throw err; }
return resp.data;
}
function convertSQL(sql) {
return sql.replace(/datetime\s*\(\s*'now'\s*\)/gi,'NOW()')
.replace(/INTEGER\s+PRIMARY\s+KEY\s+AUTOINCREMENT/gi,'INT AUTO_INCREMENT PRIMARY KEY')
.replace(/\bTEXT\s+PRIMARY\s+KEY/gi,'VARCHAR(255) PRIMARY KEY')
.replace(/\bINSERT\s+OR\s+REPLACE\b/gi,'REPLACE');
}
步骤四:损坏自愈。 sqlite-compat._openCanonical 打开即探活,命中 malformed 时 _backupCorrupt 重命名留存并 new NodeSqliteDatabaseSync(realPath) 建新库;_setPragma(db,'journal_mode = WAL') 开启预写日志保证并发安全。
步骤五:标准库↔用户库桥接。 server/services/sync-service.js 的 syncStandardToUser 将标准库(sciot_import.db 的 sciot_rules_v2/模板/提示词)增量同步进每用户私有库(user_libraries/user_),并支持"标准→用户"下发与"用户→标准"提交审核的双向桥接。
7. 权利要求书草案
权利要求1(独立权利要求). 一种工业级本地 SQLite 私有数据存储的双层隔离与跨后端适配方法,其特征在于,包括以下步骤:
- 读写分流步骤:以本地 SQLite 文件库作为云端工业数据库的本地镜像,将查询类操作定向至本地库执行,将写入类操作仍以云端数据库为权威源并在完成后同步回本地镜像,使数据查询不出本地域且保持与云端一致;
- 物理隔离步骤:为每一租户分配独立的物理数据库文件,并在请求链路层对跨租户访问进行拦截与配额控制;
- 跨后端适配步骤:提供一套统一的同步数据访问接口,当后端为 MySQL 时通过工作线程与原子同步原语将异步查询转换为同步阻塞调用,并将 SQLite 方言自动翻译为 MySQL 方言、对齐两者错误语义,使业务代码在 SQLite 与 MySQL 后端间无需改写;
- 自愈步骤:打开数据库时执行探活,对损坏的数据库文件进行带时间戳的备份留存并自动重建新库。
权利要求2(从属权利要求). 根据权利要求1所述的方法,其特征在于,所述物理隔离步骤中,租户标识经白名单过滤与长度截断以防止路径穿越,各租户数据库实例按规范化路径以单例缓存;所述请求链路层在请求体的企业标识与上下文不一致时返回拒绝响应并记录审计日志。
权利要求3(从属权利要求). 根据权利要求1所述的方法,其特征在于,所述跨后端适配步骤中,方言翻译至少覆盖日期函数、自增主键、文本主键与 INSERT OR REPLACE 四类;MySQL 的唯一键冲突错误被静默为"零影响行"以对齐 SQLite 的忽略语义;当 MySQL 初始化失败时自动回退至 SQLite 后端。
BossAgents