
前阵子公司接了一个边缘计算项目需要在 .NET 应用里落地一个本地数据库——客户端跑在 Windows 工控机上要求离线可用、断网不丢数据数据量不大但很关键。需求一拆下来团队第一个卡住的问题居然不是业务逻辑而是数据到底放在哪里。MySQL 太重装个服务还要配运维直接把 JSON 写文件又担心后面的查询、更新、索引全得自己造轮子。最后我们把目标锁定在 .NET 本地数据库的技术方案选型上把 SQLite、LiteDB、LocalDB 这一圈全部过了一遍。这篇文章就把我当时考虑过的维度、踩过的坑以及最终决策逻辑完整写出来给正在做桌面应用、离线客户端或边缘服务的 .NET 开发者一个可以直接拿来用的参考。1. 先说结论本地数据库不是越强越好部署形态才是第一道分水岭很多朋友选型时习惯先比功能列表谁支持并发、谁支持加密、谁支持存储过程比了一圈后发现项目根本用不上那么多能力。我自己吃过这个亏最初做桌面客户端时一上来就想上完整版 SQL Server理由很朴素公司里大家都熟 T-SQL出了问题也好找人看。结果客户现场是一台没有外网、配置也不高的老旧电脑光装 SQL Server 就把安装包搞得巨大后来还被运维抱怨说“一个破单机软件怎么还要装数据库服务”。所以我后来给自己定了一条规矩聊本地数据库之前先想清楚它在本项目里的部署形态再谈功能。所谓本地数据库严格来说指的是嵌入在应用程序进程内的数据库引擎数据以文件形式存在本地磁盘不需要单独部署一个数据库服务进程也不需要专门的 DBA 去维护。它和传统客户端/服务器数据库的最大区别就在这SQL Server、MySQL 这类是要有一个常驻服务程序通过 TCP/IP 连过去而 SQLite、LiteDB 这种是直接被你的进程加载读写文件外部看起来就像是一个高级点的文件读写库。1.1 一句大白话定义“本地数据库”为了照顾刚开始接触这个概念的读者我用最通俗的方式解释一下。本地数据库就是把“数据库管理系统”压缩成一个库文件嵌入到你的 .NET 程序里。程序跑起来数据库引擎跟着一起跑程序退出数据库引擎也跟着停。数据不放在某个远程服务器上就躺在应用目录下的某个文件里。这种形态解决的最典型问题有三个一是离线场景设备没有网络连接数据必须在本地落盘二是安装部署简化不需要单独安装数据库服务把文件拷贝过去就能用三是数据隐私数据不经过网络只停留在用户自己的设备上。如果你正在做的项目符合其中任意一条那本地数据库基本就是绕不开的选择。1.2 选型前先过一遍这个五连问在做任何技术对比之前我建议你先拿纸笔回答下面五个问题答案会直接影响最终选型。这个清单是我从项目实战里总结出来的比单纯看数据库功能对比表要管用得多。第一这个数据库要部署到谁的机器上是自己的开发机、客户的生产电脑还是要随产品一起分发到成百上千台设备如果是客户设备安装一个需要额外运行时或服务的数据库通常就是灾难。第二数据量级大概多少几千条业务记录、几百万条日志、还是几十 GB 的文件数据不同量级对数据库引擎的要求完全不同。第三写入频率高不高是偶尔写一条业务数据还是并发环境下持续不断地写入写入并发往往是嵌入式数据库的死穴。第四团队里谁要维护这套代码大家是更习惯写 SQL还是更习惯用 LINQ 或者类似 MongoDB 的操作方式技术栈的亲近感会直接影响开发效率。第五如果未来数据量膨胀或者业务要从单机变成联网现有数据能不能平滑迁出去这个就是“退出策略”很多人都不考虑等到要迁移时才发现数据被锁死在一个冷门格式里。把这五个问题过完你其实已经能筛掉一批方案了。下面再来看具体的候选产品。2. 主流候选方案横向拆解SQLite、LiteDB、LocalDB 与那些“差点就选”的选项.NET 世界里做本地数据库绕不开的其实就那几个SQLite、LiteDB、SQL Server LocalDB再加上一些传统但已经不建议用的方案。我给它们一个一个拆开讲重点说各自的定位、优势、限制以及什么情况下选它会比较顺手。2.1 SQLite关系型场景最稳的常青树SQLite 在嵌入式数据库领域就像 Linux 在服务器领域一样属于“只要没有特殊理由选它大概率不会翻车”的存在。它是文件型关系数据库支持标准 SQL支持事务ACID 特性做得非常扎实。在 .NET 里接入 SQLite 通常用两个库一个是微软官方的 Microsoft.Data.Sqlite做 EF Core 适配时会自动拉到另一个是更老牌的 System.Data.SQLite功能和兼容性都很全。我对 SQLite 的评价是它是所有候选方案里生态最完整、踩坑资料最多、跨平台能力最强的。Windows 上用没问题Linux 服务器上用也没问题未来就算要迁移到云函数、容器环境它依然能跑。数据就是一个后缀为 .db 或 .sqlite 的文件备份直接复制文件就能带走。不过它的短板也很明确并发写入能力弱。SQLite 是多读单写的模型同一时刻只允许一个写事务。你要是把它当成一个后端服务数据库同时有几十个客户端往里插数据很快会撞上 database is locked 的报错。这在后面我会单独展开讲。2.2 LiteDB纯 C# 写出来的文档数据库LiteDB 是一个我很喜欢的项目它最大的标签是“用纯 C# 实现的嵌入式 NoSQL 数据库”。使用体验上非常接近 MongoDB数据以 BSON 文档形式存储支持索引、支持 LINQ 查询、支持事务。因为它本身就是 .NET 生态的一员所以 API 设计对 C# 开发者极其友好不需要写 SQL直接用 lambda 表达式就能查数据。举个例子在 LiteDB 里插入一条数据并查询代码大概长这样using LiteDB; using var db new LiteDatabase(myapp.db); var items db.GetCollectionOrder(orders); items.Insert(new Order { Id 1, Customer 张三, Amount 99.9m }); var result items.FindOne(x x.Customer 张三);这种写代码的方式对团队里不太熟 SQL 的同事来说特别友善。而且 LiteDB 是单文件数据库整个库就是一个 .db 文件部署同样省心还有内置的 AES 加密支持。但 LiteDB 的生态和 SQLite 相比就差了不少。它毕竟是小众项目社区规模、资料数量、问题排查经验都有限如果遇到版本升级或者边缘 case 的 bug你得有自己看源码解决问题的心理准备。所以我的倾向是数据模型偏文档型、开发节奏快、想少写 SQL 的项目可以用它但要是复杂报表查询为主还是老老实实选 SQLite。2.3 LocalDBSQL Server 体验的轻量变体但不是生产方案SQL Server LocalDB 是微软官方出品的轻量级数据库本质上是 SQL Server Express 的一个特殊运行模式。它不用注册成 Windows 服务而是跟着应用程序按需启动面向的主要场景是开发期和测试期让你在本地写代码时能获得和线上 SQL Server 近乎一致的体验。LocalDB 的连接字符串长这样Server(localdb)\\MSSQLLocalDB;DatabaseMyAppDb;Trusted_ConnectionTrue;看起来确实方便能直接用完整的 T-SQLEF Core 也能非常顺畅地对接而且未来要切换到完整 SQL Server 时改动量很小。但我必须泼一盆冷水LocalDB 不适合作为正式交付的生产本地数据库。原因特别现实——它需要在目标机器上提前安装 LocalDB 运行时。换句话说它不是那种拷贝一个文件就能跑的“绿色数据库”你的安装程序必须先装好运行时然后再考虑数据文件的事情。这对很多桌面产品来说部署成本一下子就上去了。所以我对 LocalDB 的定位非常明确开发期模拟 SQL Server 环境可以正式交付给客户当本地库慎重。2.4 其他需要避开的旧方案和冷门选手除了上面三个还顺便提一嘴那些容易被“考古资料”带偏的方案。SQL Server Compact Edition也就是 SQLCE是微软很早以前推出的嵌入式数据库当时很多 WinForms 项目用它但实际上它早就停止维护了现在没有任何理由在新项目里选它。VistaDB 也是一个纯 .NET 的商业嵌入式数据库功能不错但商业授权费用和社区活跃度是个问题预算有限的小团队一般不建议碰。还有一个冷门方向是 DuckDB.NET它是分析型嵌入式数据库列式存储适合跑复杂分析查询。但它是 OLAP 定位不适合普通业务的增删改查拿它当常规本地数据库用会很难受这里就不展开推荐了。为了让大家一眼看清差异我把几个关键项做了个对比表对比维度SQLiteLiteDBLocalDB部署形态文件型进程内嵌入文件型进程内嵌入按需启动的轻量服务需安装运行时典型数据规模GB 级都能扛越大越需优化百 MB 到 GB 级体验良好受 SQL Server Express 限制单库约 10GB查询方式标准 SQLLINQ / 文档 API完整 T-SQLC# 接入库Microsoft.Data.Sqlite、System.Data.SQLiteLiteDB 官方包Microsoft.Data.SqlClientEF Core 支持官方 Provider无自带对象映射官方 Provider并发模型单写多读单写多读支持多写并发备份方式复制文件或用 VACUUM INTO先 Checkpoint 再复制文件备份命令或分离数据库文件默认加密无需要 SQLCipher 等扩展内置 AES 加密SQL Server 安全机制跨平台极好好基于 .NET 跨平台仅 Windows这张表基本就是我当年选型时手边那张表的升级版。接下来我要讲的是那些表格里看不太出来但真正决定成败的细节。3. 真正拉开差距的五个技术维度对比表只能让人看到“有什么”真正影响项目命运的是“怎么用”。我建议任何人在选型时都从下面五个维度去打分比直接读功能清单要可靠得多。3.1 部署与分发原生库、运行时依赖怎么算部署是整个选型过程中最容易被低估的环节。SQLite 虽然使用起来是文件型数据库但它的底层引擎是 C 语言写的原生库。你在 .NET 里通过 NuGet 引用了 Microsoft.Data.Sqlite它会在生成时把对应的原生库带过来。开发机上一切正常但当你准备做单文件发布时就特别容易出问题发布出来的 exe 拿去别的机器一跑直接抛异常说 SQLite 库加载失败。这类问题不是 SQLite 独有的而是“嵌入式原生库”在 .NET 自包含发布场景里的通病。我的建议是在选型阶段就要确认目标框架和发布方式如果是 Windows 桌面应用、想用单文件发布必须在测试阶段就把 SQLitePCLRaw 相关依赖和 native 文件的处理逻辑验证一遍别等打包完交付了才发现。LiteDB 就没有这个烦恼因为它是纯 C# 实现不依赖任何原生代码发布时就是一个纯粹的托管程序集。如果你对“发布后能不能稳定跑起来”这件事特别敏感纯托管的 LiteDB 在部署层面确实少了一个坑。LocalDB 的部署问题我在前面已经强调过了它需要安装运行时这就不只是“坑”的问题了而是整个部署流程的性质都变了。这也能解释为什么很多成熟的桌面软件倾向于选择 SQLite 或 LiteDB只要分发本质上还是“拷贝文件”售后成本就低一个数量级。3.2 数据规模从几百 MB 到几十 GB 谁是分水岭数据规模这个东西在项目初期最容易被人忽视。原因很简单刚开始开发时数据量就那么点怎么看都不像会成为瓶颈等上线运行半年后再回头看日志表已经几百万行了。SQLite 在数据规模上的弹性其实比很多人想象得大。单库存储几百 MB 的数据非常轻松到 GB 级别也还能用前提是表设计合理、索引到位、查询写得规范。真到了几十 GB 级别SQLite 也不是完全不能跑但性能衰减和碎片化问题会开始变得明显你得花更多精力做维护和优化。LiteDB 的舒适区我认为是百 MB 到 GB 级别。它作为文档数据库单文档的大小和集合数量都会影响性能。超过一定规模后索引操作和复杂查询的响应时间会明显变慢但好在大多数桌面应用和边缘设备的真实数据量根本到不了那个级别。LocalDB 由于本质上是 SQL Server 引擎数据规模的上限其实是最高的受 Express 版本限制单库大约 10GB。但要注意这个上限只是数据库物理容量考虑到它是按需启动的进程模式在实际持续运行的业务里你能不能用满这 10GB又是另外一个问题了。我个人的经验判断是本地数据库项目里超过 95% 的场景数据量在 GB 级别以内这种情况下 SQLite 和 LiteDB 都够用如果预判未来数据量会持续增长到几十 GB你要考虑的可能不是换数据库而是重新审视“数据是不是都应该留在本地”。3.3 并发模型单写多读还是多写并发并发往往是本地数据库选型里最硬的一堵墙。SQLite 和 LiteDB 骨子里都是单写多读模型它们不是为高并发写入设计的。但很多第一次做桌面应用的人不懂这个写了一个后台任务定时批量插数据同时又有几个界面线程在读结果时不时报 database is locked 或者类似的写入冲突错误第一反应是数据库坏了其实是并发模型用错了。SQLite 在 WAL 模式下读写可以并行多个读和一个写可以同时进行但多个写之间仍然互斥。这个模式需要在连接建立后执行 PRAGMA 开启PRAGMA journal_modeWAL; PRAGMA busy_timeout3000;WAL 的好处是读写不互相阻塞坏处是会额外产生 -wal 文件如果程序崩溃或者没有正常关闭这个文件不能随便删否则数据可能丢失。所以在做备份和数据拷贝时需要把主库文件和 -wal 文件一起处理或者先做一次 checkpoint让 WAL 内容合并回主库。LiteDB 的并发模型类似也支持一定程度的并发读写但当写压力上来时同样会产生锁等待。真正常见且稳妥的做法是在应用层做写入串行化也就是保证同一时刻只有一个写事务进入数据库把并发写入转换成顺序写入。LocalDB 因为底层是 SQL Server 引擎并发处理能力是最强的多写并发完全不是问题。但请记住强并发和持续运行往往意味着长时间占内存和 CPU和“轻量级本地库”的初衷已经有些背离了。所以关于并发这个维度真正关键的问题不是“选哪个库并发好”而是“我的应用能不能设计成顺序写入”。如果业务场景决定了必须以多线程方式高频写入那嵌入式数据库可能本身就不适合得重新评估方案了。3.4 查询能力与生态SQL、LINQ、EF Core 的支持度查询能力和生态决定了开发团队在这个数据库上写代码的体验也决定了未来遇到难题时能找到多少参考资料。SQLite 的查询能力是标准的 SQL支持视图、触发器、索引、子查询、窗口函数从关系型数据库转过来基本没有学习成本。在 .NET 里使用 EF Core 时官方提供了完善的 SQLite Provider模型迁移、变更追踪、LINQ 查询统统都能正常工作。我做过一个对比同一个 EF Core 的项目在 SQL Server 上写好了实体模型和迁移脚本把 Provider 换成 SQLite 后绝大部分代码不需要改动。LiteDB 走的是另一条路线查询就是 LINQ和 C# 代码无缝集成不用写字符串形式的 SQL也就不会有 SQL 注入问题。但它没有 EF Core Provider只提供自己的集合和文档映射接口。如果你的项目已经重度依赖 EF CoreLiteDB 的接入成本会比 SQLite 高一些。不过如果你本来就在写仓储模式把 LiteDB 的 API 封装在仓储层里体验也非常顺。LocalDB 的查询能力就是完整 SQL Server 的查询能力T-SQL、存储过程、视图该有的都有。EF Core 支持度也是三家里最完整的毕竟都是微软自家的产品。这个维度没有绝对优劣核心取决于团队习惯。团队全员都会 SQL选 SQLite 最平滑团队是 C# 出身、更熟悉 LINQLiteDB 会带来很强的愉悦感而如果未来明确要升级到完整 SQL ServerLocalDB 作为开发期体验垫脚石最合适。需要额外提醒的是无论选哪个都要提前把 ORM 或数据访问层的抽象做好避免业务代码到处裸操作数据库。3.5 备份、迁移与加密上线第一天就要想的事备份这件事听起来应该在项目后期才考虑但我见过太多反面案例了。很多人把本地数据库当普通文件处理直接复制一份就以为备份完了。SQLite 如果开着 WAL 模式直接复制主库文件而忽略 -wal 文件轻则丢失最后一次事务重则整个库文件无法打开。这是非常危险的。在 SQLite 里做一致性备份可以执行 VACUUM INTO 命令生成一个当前一致状态的快照文件VACUUM INTO backup.db;这个命令会把当前数据库内容完整写入到一个新文件里并且包含所有已提交事务是嵌入式场景下最省心的备份方式之一。LiteDB 的策略是备份前执行 Checkpoint把日志文件合并回主库然后再复制数据库文件。加密也是大家经常到后期才想起来的需求。原生 SQLite 默认不加密所有数据都是明文存储在文件里的如果有人拿到了 .db 文件直接就能看到表结构和数据。需要加密时通常要引入 SQLCipher 这类替身封装版本。LiteDB 内置了 AES 加密创建数据库时传入密码即可。LocalDB 则可以借助 SQL Server 的安全体系但前提还是它已经被正确安装和配置。我为什么说这些要上线第一天就想好因为备份和加密一旦等数据量大了再引入迁移成本和返工风险都是几何级上升的。密码列的加密方案和数据库文件级加密方案对应用代码的影响完全不一样中途切换很容易出诡异的兼容问题。4. 按业务场景走一遍决策地图技术对比说得再多最后还是要落到自己的业务场景里。下面我就按最常见的几类场景直接给出我倾向的选型建议和理由。4.1 桌面单机工具优先考虑 SQLite 或 LiteDB如果你的应用是典型的桌面单机工具跑在 Windows 或者 macOS 上没有联网需求数据量中等那思路就很清晰了。数据模型偏关系型、有查询报表需求选 SQLite数据模型偏文档型、追求开发效率、项目里也没人想写 SQL选 LiteDB。两者的部署形态完全一样都是文件型客户拿到的就是一个数据文件。区别主要在于团队写代码的舒适度。我喜欢用 SQLite 还有一个原因就是它的数据文件可以被很多第三方工具直接打开比如 DB Browser for SQLite 或者 VS Code 插件排查问题时能直接看数据省去写导出脚本的时间。这一点在售后支持里特别好用。LiteDB 在桌面单机工具里也很有竞争力尤其是那些数据结构经常变化的工具类软件。因为它是文档型数据库加字段不用做表结构迁移。SQLite 虽然能用 ALTER TABLE 做迁移但字段多了以后每次改结构都是一次开发任务。如果你预估产品迭代期数据结构会频繁变化LiteDB 会轻松不少。4.2 边缘设备与离线服务进程内数据库怎么扛住写入压力边缘设备这类场景通常对进程稳定性要求很高程序可能七天二十四小时不退出持续不停地收数据。这里最容易踩的坑就是写入压力和进程生命周期管理。我的建议是 SQLite 加 WAL 模式同时在应用层设计一个写入队列。所有需要写入数据的业务线程不要直接怼数据库连接而是把写入请求丢进一个队列由单一后台消费者线程顺序执行。这样既保证了 SQLite 单写模型的约束又避免了多个线程同时写导致的锁冲突。同时要关注事务粒度。边缘设备上经常有批量写入需求比如每分钟攒一批传感器数据和定时上报。很多人会把每条数据单独开一个事务一条一条提交性能奇差无比。更好的做法是批量攒一攒比如一百条或者一千条一个事务单次事务的耗时明显降低整体吞吐量反而上来了。LiteDB 在边缘设备场景也能用但它的数据文件格式和日志机制在异常断电时的恢复能力我没有足够信心如果你面对的是运行环境恶劣的工控现场SQLite 的成熟度和恢复能力更让人放心。LocalDB 在边缘设备上真的要慎用它本质是进程型 SQL Server需要额外安装运行时、有进程拉起延迟关机断电时行为也更像服务型数据库。对边缘设备这种环境不可控的地方来说越少依赖系统层面的服务越好。4.3 开发期模拟 SQL ServerLocalDB 的正确用法LocalDB 最好的存在场景是你在开发一个最终会上线到 SQL Server 的应用但本地开发环境不想背一个完整 SQL Server 实例。这时候用 LocalDB 可以获得几乎一致的 T-SQL 行为EF Core 迁移脚本也能得到验证开发体验非常顺畅。我记得有个项目就是这种节奏开发期的连接字符串指向 LocalDB测试环境用 SQL Server Express生产环境用完整 SQL Server。整个过程中 EF Core 的迁移没有出过任何兼容性问题因为 LocalDB 和 SQL Server 本来就是同源的。但要注意这种情况下 LocalDB 只是开发工具不是交付物。正式版软件发布时要么直接对接线上 SQL Server要么干脆在离线场景换用 SQLite。千万别因为开发期用顺了就顺手把 LocalDB 打进安装包发给客户。4.4 从本地库平滑升级到服务端数据库的迁移路径最后一个场景虽然平时不常被提及但很重要如果产品初期是单机离线应用后期业务扩张需要联网同步数据要迁到服务端怎么办。这条路径最稳的做法是在初期就选 SQLite并且把数据访问层封装好。SQLite 的 SQL 方言和标准 SQL 差得不多后期把数据导入 SQL Server 或者 PostgreSQL 时用现成的导入工具或者自己写个小导出程序把表结构重建一遍数据用批量插入方式导入过程可控。LiteDB 的迁移路径会曲折一些因为文档型数据和关系型表结构之间存在天然的结构差异。如果计划里有服务端数据库迁移建议刚开始时尽量减少文档嵌套层级保留清晰扁平的数据结构这样后期导到关系型数据库时就不会太痛苦。我个人的习惯是无论用哪种本地库都会在系统里保留一个标准的 JSON 导出功能所有核心表都可以一键导出成 JSON。这样将来无论切换到什么数据库至少有一份通用格式的数据副本不会被某个私有格式锁死。5. 我在选型实战里踩过的坑与经验修正技术文章写到这里其实大部分问题都已经讲透了但我觉得还不够。因为很多真实问题只有真正在项目里跑过、在客户现场栽过跟头才能变成经验。这一节我把自己遇到过的几个代表性问题和解决过程完整分享出来。5.1 SQLite 的 database is locked 不是玄学最早做离线缓存服务时我用 SQLite 做消息存储后台有个线程高频写入同时 HTTP 接口线程需要读数据。跑了不到半分钟日志里就出现大量 database is locked当时第一反应是怀疑 SQLite 性能不行。后来逐条排查才发现问题根本不在 SQLite而是我开了多个连接同时写。SQLite 的单写模型决定了同一时刻只能有一个写事务多个写连接并发就会互相等锁。解决办法也很简单应用层把写操作全部串行化全局只保留一个写入连接写入操作放到独立任务队列里顺序执行。改完之后写冲突完全消失了吞吐量也没有受到影响。这里有一个额外建议如果你使用 EF Core 操作 SQLite尽量把 DbContext 的实例生命周期控制在较短范围内不要试图用一个长连接的 DbContext 在多个线程间共享。EF Core 的 DbContext 本身不是线程安全的和 SQLite 的单写模型叠加很容易产生各种诡异间歇性 bug。5.2 LocalDB 的“首次连接即卡顿”以及它本身需要安装我当初在开发期用 LocalDB 做模拟体验确实顺滑数据库文件挂在项目目录下断点调试时还能用 SQL Server Management Studio 直接连上去看数据。后来真到了要做一个演示版交付给客户时才发现问题比想象中多。首先客户机器上需要提前安装 SQL Server LocalDB 运行时安装包本身就有几十 MB而且安装过程经常要求重启或者装一堆 VC 运行库现场演示时这一幕非常尴尬。其次LocalDB 是按需启动的进程第一次连接时往往有明显延迟表现为界面卡顿几秒才出数据。这在演示版里还不致命但如果是真实业务场景每次重启软件第一下操作都卡用户体感会非常差。从那以后凡是能选文件型数据库的场景我就不再把 LocalDB 列入候选。它最合适的位置是开发人员的本机而不是客户的生产环境。5.3 LiteDB 备份与文件复制Checkpoint 不是可选项LiteDB 在单个小工具项目里表现很惊艳开发效率高代码写起来也顺手。后来我在生产环境发现一个很隐蔽的坑直接复制 .db 文件做备份恢复后发现丢了最后一部分数据。原因在于 LiteDB 的数据文件和日志机制。它在运行过程中会有尚未合并到主文件的写入日志备份时如果只是粗暴复制主文件日志里的数据就不会被带上。后来我把备份流程改成先调用数据库实例的 Checkpoint 方法再复制文件问题彻底解决。这个坑告诉我一个通用规律只要是文件型数据库在运行状态下复制文件都存在一致性问题。备份操作必须遵循数据库官方推荐的方式用官方命令生成快照或者先做日志合并不能想当然地按普通文件处理。5.4 单文件发布后弹出 SQLite 加载失败原生库问题还有一次是在打包阶段踩的坑。项目用的 SQLite开发机和测试机上都运行正常但用 .NET 的单文件发布模式打包后拿到一台全新机器上一运行直接报错提示无法加载 SQLite 模块。排查后发现是单文件发布时SQLite 依赖的原生库没有正确打包进单文件程序集或者说管理器没有在正确的目录释放原生库。这个问题在 .NET 生态里不算新鲜处理方式通常是显式引用 SQLitePCLRaw.bundle_e_sqlite3 包并在发布配置中确认 native 库被包含进去。这也是为什么我在前面反复强调部署形态最好在选型阶段就确认因为不同的打包发布策略会让同一款数据库在交付环节体验完全不同。如果不想在生产物交付阶段临时回头处理这类问题可以提前写一个自动化测试在 CI 里做一次单文件发布再启动一个干净容器或虚拟机跑一下冒烟用例专门验证数据库的加载和写入读取流程。5.5 始终先把“退出策略”写好最后一个经验可能有点抽象但我觉得是整篇里最重要的一条不管选型时拍板选了哪个数据库都要把“退出策略”写好。所谓退出策略就是将来想换成别的数据库时你准备怎么把数据完整搬出去。我有个朋友的项目用了一个非常小众的嵌入式数据库数据库文件格式完全不透明官方工具也少。后来客户要求系统必须支持实时数据上报需要把离线数据同步到服务端他们想尽办法最后只能逐条遍历数据然后转成 JSON还得处理各种类型转换问题足足折腾了两周。如果在选型时就考虑退出策略做法很简单所有核心实体的读写都经过仓储层仓储层同时对 JSON 导出提供支持任何实体集合都能一键序列化成通用数据格式。这样无论将来换数据库还是对接云端基础数据都是通用的不会被某个私有格式绑架。我个人在选型时最看重的第一件事永远是部署形态而不是功能列表。功能再强部署到客户现场跑不起来一切都等于零。这个项目最后我们选的是 SQLite 加 WAL 模式配合应用层写入队列和定期 VACUUM INTO 备份运行几个月下来非常稳定。如果让我再选一次我还是会走同样的路径。最后再分享一个小技巧无论你最终选了哪个本地数据库开工前先把备份和迁移方案写进技术方案文档里哪怕只是几句话。就这几句话能帮你躲过后面的绝大多数数据事故。