ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

VB6老项目迁移SQLite:litex_sqlite封装库实战指南

VB6老项目迁移SQLite:litex_sqlite封装库实战指南 简介面向 Visual Basic 6 开发者的 SQLite 集成工具包 litex_sqlite让 VB6 程序无需安装数据库服务端即可通过嵌入式引擎使用 SQLite适合需要本地存储、追求轻量高效的桌面应用场景对有一定 VB6 基础、希望为程序增加本地数据库能力的开发者尤为适用。压缩包共 134 个文件、约 1.5MB包含 C/C 源文件.h/.cpp/.c、DLL/LIB 库文件、VB6 工程文件.bas/.frm/.vbp、HTML 说明文档及若干 EXE 工具并附带 Visual Studio 工作区与解决方案文件目录结构较为清晰便于按需查找。其中附带的 SQLite 使用说明文档详细介绍了在 VB6 中配置项目、导入库、调用 API 的具体步骤配合注册批处理脚本和示例工程可帮助读者完成 DLL 注册、连接数据库及建表、插入、查询、更新等操作同时覆盖常见问题排错思路还可结合 ADODB 或 DAO 方式操作数据库便于对比不同访问路径的差异。已有 766 人学习下载是 VB6 开发者接入 SQLite 的实用参考资源。1. 老项目也要用上 SQLite为什么 litex_sqlite 值得留在 VB6 工具箱还在维护 VB6 老项目的工程师多半都撞过同一个墙Access 库文件涨到几百 MB 就开始卡想换成 SQLite 却不知道从哪下手——VB6 要声明几十个 sqlite3.dll 的 C API 函数光是处理指针和回调就能劝退一半人。litex_sqlite 就是干这个用的它把 SQLite 的核心能力封装成 VB6 能直接调用的对象打开库、建表、增删改查、事务、参数绑定都变成几行代码的事。适合还在用 VB6 维护进销存、工控数据采集、学校管理系统这类项目的工程师不想推翻重写业务逻辑只想把数据库底座换成能撑到百万行级的 SQLite。下面按部署、API、事务、避坑、进阶的顺序把这套东西讲透。2. 从 Access 换到 SQLitelitex_sqlite 的部署方式与安装三步2.1 单文件部署 vs Jet 引擎换库的第一个理由VB6 项目里最常见的数据库搭配是 AccessJet/ACE但用久了会踩到几个硬钉子。第一是 ACE 引擎跟着 Office 版本走客户机器上没装 Office 就得补运行库32 位和 64 位还经常装错第二是 Access 的锁机制在多人写入时不太给力表锁一旦撞上前台界面直接假死第三是数据库文件在异常断电后经常只留一个几百 KB 的临时文件正经数据全没了。SQLite 把这些问题都绕开了。它本身就是一个嵌入式的 C 库VB6 进程加载它之后数据库就是一个 .db 文件不需要额外的数据库服务也不需要安装任何引擎。SQLite 支持标准的 SQL 语法事务是 ACID 的单文件拷贝就能迁移备份。从 Access 换到 SQLite对业务代码的影响其实很小——绝大多数 SELECT、INSERT、UPDATE、DELETE 语句可以直接平移真正要改的是连接方式、参数写法和字段类型判断这三块。那为什么不直接调 sqlite3.dll 的原始 API因为原生接口对 VB6 太不友好了。sqlite3_open 要传指针地址sqlite3_prepare_v2 要处理 sqlite3_stmt 句柄读取查询结果要通过 sqlite3_column_text 这类函数逐列取数据还要用 sqlite3_bind_text 手动绑定参数。一套流程写下来光 Declare 语句就有三四十行而且 VB6 的 String 类型和 C 语言的 char* 之间存在编码转换问题中文场景下特别容易翻车。litex_sqlite 这类封装库的价值就是把这一层脏活累活收进 DLL 里对外暴露对象和方法让 VB6 工程师用熟悉的 CreateObject、方法调用、属性读取的节奏来操作 SQLite。2.2 litex_sqlite 的封装结构DLL、类模块与 API 的分工我拆过几个 VB6 可用的 SQLite 封装结构上大体是两种形态。一种是 ActiveX DLL 方式把 SQLite 的 C API 封装成 COM 组件VB6 工程里通过「工程—引用」勾选后直接用 New 创建对象。另一种是「sqlite3.dll 类模块」方式VB6 工程里放一个或多个 .cls 文件类内部通过 Declare 声明调用 sqlite3.dll 的导出函数工程里不需要注册任何组件。litex_sqlite 属于前者它对 VB6 更友好因为所有对象模型都在类型库里写代码时有属性提示和成员列表不容易写错函数名。无论哪种形态底层的 sqlite3.dll 都必须匹配 VB6 的进程位数。VB6 的 EXE 编译出来是 32 位进程所以 sqlite3.dll 必须用 32 位版本如果你把 64 位的 sqlite3.dll 放到 System32 里VB6 一调用就直接报「入口点错误」。正确的位置是 SysWOW64或者干脆放在应用程序目录里让 VB6 直接加载同目录的 DLL。要注意的是litex_sqlite 本身可能内置了一个特定版本的 SQLite 核心也可能依赖外部的 sqlite3.dll安装前最好看一下压缩包里的说明确认它是否能和项目现有环境共存。2.3 安装与注册让 VB6 工程引用 litex_sqlite 的三步操作拿到资源包之后安装流程非常固定我在新机器上一般走三步整个过程不超过两分钟。第一步把 litex_sqlite.dll 和它依赖的 sqlite3.dll如果有的话复制到你的应用程序目录或者复制到 C:\Windows\SysWOW64。我习惯放应用目录这样重装系统、拷贝整个项目文件夹到别的机器时DLL 跟着走不会出现目标机器上注册路径失效的问题。第二步注册 ActiveX DLL。在管理员命令行里执行cd C:\你的应用目录 regsvr32 /s litex_sqlite.dll这里 /s 参数表示静默注册不弹成功提示框。注册成功后再打开 VB6 开发环境如果 regsvr32 报错常见的两个原因是DLL 依赖的 sqlite3.dll 不在同目录或者当前命令行没有以管理员权限打开。注册是必要的一步因为类型库信息要写进注册表VB6 的「引用」对话框才能列出它。第三步在 VB6 工程里添加引用。菜单栏选「工程—引用」在列表里勾选名为 Litex SQLite 或类似名称的条目点击确定。然后在代码窗口里测试实例化Dim db As LitexConnection Set db New LitexConnection MsgBox db.Version Set db Nothing这段代码只是为了验证封装是否可用。LitexConnection 是封装库对外暴露的主要连接对象Version 属性会返回底层 SQLite 的版本字符串能弹出这个值就说明引用配置成功。如果编译时报「用户定义类型未定义」多半是引用没勾上或者 DLL 注册时类型库没写进注册表回到第二步重新注册即可。3. litex_sqlite 核心 API 实战连接、建表与增删改查3.1 打开连接连接串参数与关闭时机litex_sqlite 的使用节奏和 ADODB.Connection 类似先创建连接对象再打开数据库文件。下面是最基本的打开方式Dim db As LitexConnection Set db New LitexConnection 打开数据库文件文件不存在时会自动创建 db.Open App.Path \data.db 判断是否连接成功 If db.IsOpen Then Debug.Print 数据库已打开 End If 用完务必关闭并释放 db.Close Set db Nothing这里有个值得注意的细节数据库路径建议用 App.Path 拼接绝对路径不要用 CurrentDir。VB6 里 CurrentDir 是全局性的如果用户通过快捷方式启动程序工作目录可能指向桌面这时候相对路径解析出来的文件位置会和你预期的完全不同。用 App.Path 拼完整路径文件一定落在 exe 所在目录排查问题也直观。Open 方法通常还能接收一些附加参数比如只读模式、连接超时、同步模式等。常见做法是在打开后通过连接对象的属性或者 PRAGMA 语句来设置例如设置连接超时防止并发写入时立即抛错db.Open App.Path \data.db db.SetTimeout 5000 单位毫秒锁等待上限 5 秒 db.Execute PRAGMA busy_timeout 5000SetTimeout 是封装库提供的属性写法busy_timeout 是 SQLite 原生的锁等待设置两条都写上不会冲突。对单机应用来讲busy_timeout 设为 3000 到 5000 毫秒是一个比较稳妥的范围太短会导致偶发的写入失败太长会让界面在极端情况下卡住。3.2 建表与写操作Execute 返回值和错误信息的读取建表和写入操作都通过 Execute 方法完成。Execute 接收一条 SQL 语句返回值一般是受影响的行数如果语句出错可以通过连接对象的 LastError 属性拿到错误描述。 建表语句 Dim sql As String sql CREATE TABLE IF NOT EXISTS users ( _ id INTEGER PRIMARY KEY AUTOINCREMENT, _ name TEXT NOT NULL, _ age INTEGER, _ created_at TEXT DEFAULT (datetime(now)) _ ) db.Execute sql 插入一条数据 db.Execute INSERT INTO users(name, age) VALUES(张三, 28) 更新数据 Dim rows As Long rows db.Execute UPDATE users SET age 29 WHERE name 张三 Debug.Print 受影响行数 rowsAUTOINCREMENT 是 SQLite 的自增主键写法有一点要清楚SQLite 的 INTEGER PRIMARY KEY 本身就会自增AUTOINCREMENT 的额外作用是保证主键不重复复用已删除的编号。对业务表来说用 INTEGER PRIMARY KEY 就够了加上 AUTOINCREMENT 会多维护一个 sqlite_sequence 内部表纯属浪费。Execute 的返回值不一定靠谱不同封装库的实现不一样有的返回受影响行数有的直接返回布尔值。我一般不看返回值判断成功失败而是执行完立刻检查 LastError。上面 UPDATE 的例子返回了受影响行数这是 SQLite 标准 API 提供的信息因为 C API 里 sqlite3_exec 有回调参数可以收集受影响行数封装库愿意的话确实能回传。3.3 查询结果集逐行遍历与字段值转换查询操作和写操作不同不能只用 Execute 一条路走到头。litex_sqlite 一般会提供一个查询方法返回记录集对象封装方式类似 ADODB.Recordset。Dim rs As LitexRecordset Set rs db.Query(SELECT id, name, age FROM users WHERE age ?, Null) Do While Not rs.EOF Debug.Print ID: rs.GetValue(0) Debug.Print 姓名: rs.GetValue(1) Debug.Print 年龄: rs.GetValue(2) rs.MoveNext Loop rs.Close Set rs Nothing这段代码是典型的查询流程Query 方法执行 SQL返回记录集EOF 判断是否遍历完GetValue 按下标取字段值MoveNext 移动到下一行用完后 Close 并置空。需要注意的是Query 方法第一个参数是 SQL 语句第二个参数通常用来传参数数组后面讲参数绑定的时候会展开。GetValue 返回的是 Variant 类型实际数据类型由 SQLite 动态决定。SQLite 的列没有固定类型这一行存的是 TEXT下一行可能存的是数字。因此取值后要用 VarType 或者类型转换函数做判断。比如上面的 age 字段如果某一行的值是空值 NULLGetValue 返回的是 vbNull直接当成数字参与运算会报类型不匹配。更稳的写法是先判断Dim vAge As Variant vAge rs.GetValue(2) If IsNull(vAge) Then Debug.Print 年龄为空 Else Debug.Print 年龄: CInt(vAge) End If取字段值还有一个选择按字段名下标的写法 vs 按字段名的写法。下标方式性能好不受字段名改动影响字段名方式可读性好。litetx 这类封装通常两种都支持。我建议在代码量少的项目里用下标因为 SQLite 查询结果的列顺序由 SELECT 语句决定只要 SQL 是你在维护下标不会乱。3.4 参数绑定告别拼 SQL 字符串的写法直接用 拼接 SQL 字符串在 VB6 里写起来最快但有两个问题一是日期和字符串类型要自己加单引号漏加就会报语法错误二是用户输入内容里如果包含单引号会产生 SQL 注入甚至直接让程序崩溃。litex_sqlite 支持参数绑定也就是用 ? 占位符再把实际值通过绑定方法传进去。Dim cmd As LitexCommand Set cmd db.CreateCommand(INSERT INTO users(name, age) VALUES(?, ?)) cmd.BindText 1, userName userName 是 VB6 String 变量 cmd.BindInt 2, userAge userAge 是 Long 变量 cmd.Execute cmd.Close Set cmd Nothing这里 CreateCommand 生成一个命令对象参数序号从 1 开始BindText 绑定字符串BindInt 绑定整数。绑定之后执行 Execute和直接执行 SQL 效果一样但不用关心字符串里的单引号和特殊字符。BindText 内部会做编码转换这是 litex_sqlite 这类库替你做掉的重要工作。SQLite 在内部按 UTF-8 存储文本而 VB6 的 String 是 UTF-16如果直接用内存地址传字符串SQLite 读到的会是乱码。封装库的 BindText 方法一般在内部先转成 UTF-8 字节数组再传给 SQLite 的绑定函数。这也是我强烈建议用参数绑定的原因之一——它顺手解决了一半中文乱码问题。另一半乱码出现在读取端后面避坑章节专门讲。4. 事务与批量写入把 1000 条数据从秒级压到毫秒级4.1 事务三件套Begin、Commit 与 Rollback 的标准用法SQLite 默认是自动提交模式每一条 INSERT 语句都是一个独立事务这意味着每条写入都要经过一次磁盘同步。如果你循环写 1000 条数据SQLite 就要同步 1000 次磁盘耗时往往在几十秒以上。解决办法是手动开启事务把 1000 条写入合并成一个事务磁盘只在最终提交时同步一次。litex_sqlite 的事务接口一般是这样db.BeginTransaction On Error GoTo ErrHandler db.Execute INSERT INTO log(message) VALUES(第一条) db.Execute INSERT INTO log(message) VALUES(第二条) db.Commit Exit Sub ErrHandler: db.Rollback MsgBox 写入失败事务已回滚 db.LastErrorBeginTransaction 开启事务Commit 提交Rollback 回滚。这三者的使用规则里最容易出错的是事务开启后任何一条 SQL 出错事务并不会自动回滚而是保持开启状态。如果不手动 Rollback后续所有写操作都会堆积在这个悬空事务里连接关闭时 SQLite 会自动回滚但你会发现前面几条成功执行的数据突然不见了。所以事务块里必须有 On Error GoTo出错统一走回滚分支。事务对读取也有影响事务开启后其他连接在同一时间看不到未提交的数据这是 SQLite 的隔离机制。一般单机应用不要长时间挂着一个写事务事务块里的代码执行得越快越好不要在事务中间弹 MsgBox 或者做耗时的文件操作。4.2 批量写入的节奏准备语句复用与提交间隔有了事务批量写入的性能已经上了一个台阶。但如果你要写入的是几万条数据还可以再优化一层复用准备语句而不是每条都重新解析 SQL。litex_sqlite 的 CreateCommand 做了预编译可以在循环外只创建一次命令对象循环里反复绑定参数最后统一提交。Dim cmd As LitexCommand Dim i As Long Set cmd db.CreateCommand(INSERT INTO log(message, ts) VALUES(?, ?)) db.BeginTransaction For i 1 To 10000 cmd.BindText 1, 日志条目 CStr(i) cmd.BindText 2, Format$(Now, yyyy-mm-dd hh:nn:ss) cmd.Execute Next db.Commit cmd.Close Set cmd Nothing这里的关键动作有两个CreateCommand 放在循环外只解析一次 SQL 语句SQLite 内部会把它编译成字节码后续执行直接复用事务包裹整个循环10 万条以内的批量写入用这种写法一般能在几百毫秒到两三秒内完成和逐条自动提交的速度差异是两个数量级。提交间隔的问题要单独说一下。把 10000 条全部包在一个事务里如果中途断电或程序崩溃这 10000 条全没了。对日志类数据来说无所谓但对业务数据很多人会每 500 条或 1000 条提交一次兼顾速度和安全性。具体的间隔取决于你对丢数据的容忍度也取决于磁盘性能。4.3 并发读写SQLite 锁机制与 VB6 端的重试策略SQLite 的并发模型是库级锁写操作会拿独占锁其他连接在写事务未提交前不能写。读操作可以并发但在 WAL 模式之外读会被写阻塞。对 VB6 单机应用来说最常见的冲突场景是主程序在后台线程或定时器里写入数据同时又有一个查询窗口在读取两个连接撞在一起SQLite 返回 database is locked。这时候不要试图去解锁SQLite 没有这种操作。正确的处理方式是设置 busy_timeout 让 SQLite 自己等待或者在 VB6 端检测到锁错误后延迟重试。Dim retryCount As Integer Dim success As Boolean retryCount 0 success False Do While (Not success) And (retryCount 5) If db.Execute(UPDATE stock SET qty qty - 1 WHERE id 1) Then success True Else If InStr(db.LastError, locked) 0 Then retryCount retryCount 1 Sleep 200 等待 200 毫秒后重试 Else Exit Do End If End If LoopSleep 函数在 VB6 里需要声明或者直接用 Windows API 的 Sleep。这个重试逻辑的核心是只对 locked 错误重试其他错误立即退出否则会把语法错误也当成可重试的掩盖了真正的问题。重试次数和间隔要控制住5 次、200 毫秒是比较常见的组合再多就会让界面失去响应。5. VB6 用 sqlite 的避坑笔记从 DLL 找不到到中文乱码的 6 条记录5.1 运行时提示无法找到 DLL现象程序一启动就弹窗提示无法找到 litex_sqlite.dll 或指定的 DLL 不存在有时还伴随内存位置访问无效。原因VB6 编译后的程序是 32 位进程它按顺序查找 DLL应用程序目录 → SysWOW64 → System32 → PATH 环境变量。如果 litex_sqlite.dll 和 sqlite3.dll 没有放在应用目录也没有注册到 SysWOW64系统就找不到。另一种隐蔽情况是只有 litex_sqlite.dll 放进去了但它依赖的 sqlite3.dll 没放导致加载到一半失败。解决把资源包里的所有 DLL 放到同一目录不管它们是放在应用目录还是 SysWOW64都保证同目录内互相可见。用 regsvr32 注册 ActiveX DLL 只解决类型库注册问题不解决依赖 DLL 的路径问题依赖文件必须物理存在。5.2 写入的中文显示成乱码现象用 litex_sqlite 插入中文数据用 DB Browser for SQLite 打开看是乱码或者反过来——DB Browser 里写的中文VB6 读出来是问号。原因VB6 的 String 是 UTF-16 编码SQLite 内部存储文本用 UTF-8。如果你用直接拼接 SQL 的方式插入中文没有做编码转换SQLite 会把 UTF-16 的内存内容当作 UTF-8 解析存进去的自然就是乱码。读取端同理取出来的是 UTF-8 字节流VB6 直接当 String 用也是乱码。解决优先用封装库的参数绑定方法内部会处理 UTF-8 转换。如果封装库没有提供绑定方法只能拼 SQL那必须手动转码。VB6 里常见的做法是调用 MultiByteToWideChar 和 WideCharToMultiByte 这一对 API先把 VB6 String 转成 UTF-8 字节数组拼进 SQL 时再按字节拼。这一步很繁琐所以选型时务必确认封装库支持参数绑定。5.3 attempt to write a readonly database现象程序运行正常但一执行 INSERT 或 UPDATE 就报错错误信息是 SQLITE_READONLY中文环境下有时被封装库翻译成尝试写入只读数据库。原因这个错误不一定是文件被设置了只读更常见的是文件所在目录没有写权限。SQLite 写入时会在数据库文件旁边创建一个 journal 文件如果目录不允许创建文件写操作就会失败。程序装在 Program Files 下、U 盘根目录、或者 Windows 权限收紧的用户目录都容易触发。解决把数据库文件放到一个有写权限的目录比如程序自己的数据目录或者用户文档目录。检查文件属性的只读勾选同时检查目录的 NTFS 权限。如果数据库文件本身可写但目录不可写SQLite 会报同样的错这一点最容易忽略。5.4 database is locked 报错频率过高现象两个连接同时操作数据库其中一个执行写入时报错 database is locked即便设置了 busy_timeout 也偶尔失败。原因SQLite 对并发的处理是写事务开始后整个数据库文件被独占锁保护其他写操作必须等待。busy_timeout 只能让 SQLite 在锁等待期间继续尝试但如果在超时时间内锁没释放还是会报错。VB6 多窗体项目里很容易出现两个窗体各自创建了一个连接对象都没关闭互相阻塞。解决先检查是否所有连接对象都正确关闭并置空。然后用上一章的重试循环做兜底把 locked 错误当作稍后再试而不是彻底失败。另外打开连接时设置 PRAGMA journal_mode WAL能让读写并发提高不少WAL 模式下读操作不会被写事务阻塞。5.5 读取长文本时被截断现象某个字段存了几千字的备注VB6 读出来只有一半或者变成一个空字符串。原因封装库读取文本时可能按固定的缓冲区长度来分配内存比如只分配 255 字节或 512 字节。SQLite 的 TEXT 字段长度没有上限缓冲区不够就会截断。另一种情况是字段里有 NULL封装库没有正确处理直接返回了空串。解决查看封装库是否提供了读取大字段的专用方法比如 GetTextBlob 或者按字节读的接口。如果没有那就改用 sqlite3_column_bytes 配合逐字节读取的方式来处理长字段。这类问题在封装库的文档里通常写得很隐晦测试时最好造一条 2000 字以上的数据直接验证。5.6 数据库文件损坏提示 malformed现象程序崩溃或断电后再打开数据库报错 database disk image is malformed数据无法读取。原因SQLite 在写入时依赖 journal 文件保证原子性如果操作系统在写入中途崩溃或者有人在数据库正在写入时直接复制了 .db 文件就可能留下不一致的状态。VB6 程序里最常见的触发动作是用 FileCopy 直接备份正在使用的数据库文件。解决备份数据库不要用 FileCopy要用 SQLite 的在线备份接口下一章详细写。程序退出时先 Close 连接再允许用户操作文件。已经损坏的文件可以尝试用 DB Browser for SQLite 的完整性检查和导出功能尽量捞数据但最重要的是防患于未然——每次升级版本前用 VACUUM 命令压缩并重建数据库文件能清理内部碎片降低损坏概率。6. 让 litex_sqlite 更顺手Unicode 转换、在线备份与性能验证6.1 中文与 UnicodeVB6 String 转 UTF-8 再入库参数绑定解决了一部分中文问题但如果你的封装库绑定方法处理得不完善或者你要把数据以纯文本方式导出、跨平台交换还需要手动掌握 VB6 到 UTF-8 的转换。VD6 里没有直接的 UTF-8 转换函数常见的做法是调用 Windows API。Private Declare Function WideCharToMultiByte Lib kernel32 _ (ByVal CodePage As Long, ByVal dwFlags As Long, _ ByVal lpWideCharStr As Long, ByVal cchWideChar As Long, _ ByVal lpMultiByteStr As String, ByVal cbMultiByte As Long, _ ByVal lpDefaultChar As String, ByVal lpUsedDefaultChar As Long) As Long Public Function StrToUTF8(ByVal sText As String) As Byte() Dim lLen As Long Dim bBuf() As Byte lLen WideCharToMultiByte(65001, 0, StrPtr(sText), -1, , 0, , 0) ReDim bBuf(0 To lLen - 1) WideCharToMultiByte 65001, 0, StrPtr(sText), -1, bBuf(0), lLen, , 0 StrToUTF8 bBuf End Function代码里 65001 就是 UTF-8 的代码页编号。WideCharToMultiByte 先把长度算出来再分配字节数组第二次调用把内容写进去。这套 API 是 Windows 系统自带的不需要额外引入任何库。这里要注意的是如果字段要存中文文件名、emoji 或者生僻字必须走这种显式转换参数绑定方法内部可能处理的字符集范围有限。6.2 在线备份不关库也能安全拷贝数据文件VB6 项目换库之后备份逻辑也要跟着换。以前用 FileCopy 拷贝 Access 文件数据库可能处于打开状态拷出来的文件经常是坏的。SQLite 提供了在线备份接口能在数据库被程序正常使用的同时生成一份一致的备份文件。litex_sqlite 如果封装了 backup 方法调用方式通常是Dim backupOk As Boolean backupOk db.BackupTo(App.Path \backup\data_backup.db) If backupOk Then Debug.Print 备份完成 Else Debug.Print 备份失败 db.LastError End If如果没有封装也可以用 SQLite 的 VACUUM INTO 命令这一招在较新的 SQLite 版本里可用db.Execute VACUUM INTO App.Path \backup\data_backup.dbVACUUM INTO 会把当前数据库的内容复制到一个新文件并且自动执行整理相当于一次压缩备份。它和在线备份接口的区别是VACUUM INTO 生成的文件是优化过的体积更小但执行期间会短暂占用写锁所以要在程序空闲时做。我一般把备份动作放在定时器里凌晨执行或者放在程序退出前执行。6.3 性能与完整性验证三个可复用的检查习惯换库后最怕的不是功能出错而是数据在某个角落悄悄丢了。我给自己定了一套固定的检查流程现在每次交付 VB6SQLite 项目都强制走一遍。第一个习惯每次打开数据库连接后执行一次完整性检查。Dim rs As LitexRecordset Set rs db.Query(PRAGMA integrity_check, Null) Debug.Print rs.GetValue(0) 输出 ok 表示数据库完好 rs.Close Set rs Nothingintegrity_check 会逐页校验数据库文件正常情况下第一行返回字符串 ok。如果返回其他内容说明数据库已经有隐患要立刻用备份恢复。第二个习惯批量写入前后对比记录总数。写入前查一次 COUNT(*)写入完成后再查一次差值必须等于预期写入条数。这个检查看起来多余但在事务回滚和重试逻辑存在的情况下它是最可靠的数据守恒验证。第三个习惯用 DB Browser for SQLite 做交叉验证。程序里写入的数据在 DB Browser 里查看能不能正常显示中文、数字精度是否对DB Browser 里手工修改的数据程序重启后能不能读出来。这一步主要排查编码和类型匹配问题。从那以后我每次换库、升级封装版本都强制走一遍这三项检查确认无误后才敢让客户切到新环境。希望帮到你。本文还有配套的精品资源点击获取
返回列表