推荐使用 microsoft.data.sqlite,需用绝对路径构造连接字符串并捕获 sqliteexception;ef core 方式需手动处理外键与迁移限制;避免 system.data.sqlite;wal 模式可优化读并发,但高写并发应换库。

用 SqliteConnection 打开数据库是最直接的方式
SQLite 在 C# 中没有内置支持,必须通过第三方 ADO.NET 提供程序,最常用的是 Microsoft.Data.Sqlite(推荐)或 System.Data.SQLite(较老,维护弱)。用 SqliteConnection 是最底层、最可控的连接方式。
关键点:连接字符串里不能写 Data Source=xxx.db 就完事,路径必须是绝对路径或明确相对于当前工作目录;否则运行时抛 SqliteException: unable to open database file。
-
Microsoft.Data.Sqlite包需安装:dotnet add package Microsoft.Data.Sqlite - 连接字符串示例:
"Data Source=app.db"—— 若app.db不在当前目录(如bin/Debug/net8.0/),会静默失败 - 建议显式构造绝对路径:
Path.Join(AppContext.BaseDirectory, "app.db") - 打开连接后务必
try/catch捕获SqliteException,它不继承自IOException,容易漏处理
用 DbContext + EF Core 是最常用的生产级写法
如果你项目已用 EF Core,直接配 SQLite 提供程序比手写 ADO.NET 更安全、更易维护。但要注意它默认不启用外键约束,且迁移行为和 SQL Server 不同。
常见坑:执行 dotnet ef migrations add Init 后,生成的迁移代码里可能含 SQLite 不支持的语法(比如 ALTER TABLE ... ADD COLUMN ... NOT NULL),导致 Update-Database 失败。
- 启用外键:
options.EnableSensitiveDataLogging().UseSqlite(connectionString, b => b.MigrationsAssembly("YourAssemblyName").UseRelationalNulls()) - SQLite 不支持列默认值在迁移中自动加
NOT NULL,需手动在Up(MigrationBuilder)里用Sql()补充 -
DbContext实例不能长期持有,应按请求生命周期创建(如 ASP.NET Core 中注册为Scoped)
别用 System.Data.SQLite 新项目
这个库曾是主流,但现在已多年未更新,对 .NET 6+ 的 Span<byte></byte>、异步 I/O 支持差,且 NuGet 包自带 x86/x64 混合 native 二进制,容易引发 DllNotFoundException 或平台不匹配问题。
典型错误信息:Unable to load DLL 'SQLite.Interop.dll': The specified module could not be found —— 这不是路径问题,是运行时架构(x64 vs ARM64)和 interop dll 不匹配。
- 若旧项目还在用,至少锁定
System.Data.SQLite.Core1.0.115.5 及以上(修复了 .NET 5+ TLS 握手崩溃) - 新项目一律用
Microsoft.Data.Sqlite,它纯托管实现,无 native 依赖,跨平台稳定 - 它的
SqliteCommand不支持命名参数(如@id),只认?占位符,顺序必须严格对应Parameters.Add()
文件锁和并发写入是 SQLite 最容易被忽略的瓶颈
SQLite 默认是“写阻塞”模型:任意一个连接执行 INSERT/UPDATE/DELETE,整个数据库文件会被加独占锁,其他连接的写操作会立即报错 SQLITE_BUSY(对应 C# 异常 SqliteException: database is locked)。
这不是代码写错了,是设计使然。尤其在 Web 应用里多个请求同时写,很容易触发。
- 解决思路不是加重试逻辑,而是减少写事务粒度:把大事务拆成小事务,避免在事务里做 HTTP 调用或文件读写
- 连接字符串可加
BusyTimeout=5000(毫秒),让命令等待锁释放,但治标不治本 - 读多写少场景下,可用 WAL 模式:
"Data Source=app.db;Mode=ReadWriteCreate;Journal Mode=WAL;",能提升并发读性能,但不解决写冲突 - 真正高并发写需求,SQLite 本身就不适合——该换 PostgreSQL 或 LiteDB 这类文档型嵌入库了
SQLite 的“轻量”是双刃剑:开箱即用,但锁机制、事务边界、路径解析这些细节一旦出错,现象隐蔽、定位困难。尤其在容器或 ClickOnce 部署时,AppContext.BaseDirectory 和实际 DB 文件位置错位,是最常卡住人的点。











