SQLiteConnection 打不开数据库文件需检查路径和权限;ExecuteNonQuery 无报错但未写入须调用 Commit;DateTime 存储应转字符串或统一用 Ticks;多线程需各自新建连接,避免共享实例。

SQLiteConnection 打不开数据库文件?检查路径和权限
最常见的错误是 SQLiteConnection 构造时抛出 System.IO.FileNotFoundException 或提示“unable to open database file”。这不是 SQLite 本身的问题,而是 .NET 运行时找不到或无法写入指定路径。
- 用相对路径(比如
"data.db")时,实际位置是进程当前工作目录,不是项目根目录或bin/Debug—— 调试时可在代码开头加Console.WriteLine(Directory.GetCurrentDirectory());确认 - Windows 上若程序以管理员身份运行,但数据库放在
C:\Program Files\...下,普通用户权限写入会失败;推荐统一用Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)拼路径 - 确保已安装
Microsoft.Data.SqliteNuGet 包(.NET 5+ 推荐)或System.Data.SQLite(兼容旧版),别混用两套 API
ExecuteNonQuery 插入没报错却没写入?记得调用 Commit
如果你用 SQLiteTransaction 包裹了 Insert,但没调用 transaction.Commit(),数据就真的不会落盘——它卡在事务里,连接一关就回滚。这个行为和 SQL Server 或 PostgreSQL 一致,但新手常以为“没报错=成功”。
- 不手动开事务时,每个
ExecuteNonQuery默认是自动提交的,此时不用管Commit - 开了事务就必须显式
Commit()或Rollback(),哪怕只执行一条INSERT - 建议用
using块包裹SQLiteTransaction,并在 finally 里判断状态再提交,避免异常导致悬挂事务
DateTime 字段存进去变成 1970-01-01?注意 SQLite 的类型亲和性
SQLite 本身没有原生 DATETIME 类型,它靠字段名后缀(如 created_at)、值格式(ISO8601 字符串)和你传入的 .NET 类型共同决定怎么存。直接传 DateTime 对象通常会被转成 ticks 长整型,读出来就可能错乱。
- 最稳做法:插入前用
dateTime.ToString("yyyy-MM-dd HH:mm:ss")转成字符串,列类型声明为TEXT - 如果坚持用数值型,统一用
dateTime.ToUniversalTime().Ticks存,读取时用new DateTime(ticks, DateTimeKind.Utc) - 别依赖
DateTime.Now直接塞进参数——Microsoft.Data.Sqlite会按默认规则映射,不同版本行为可能微调
多线程写同一个 db 文件崩了?别共享 SQLiteConnection 实例
SQLiteConnection 不是线程安全的。多个线程共用一个实例并发调用 ExecuteReader 或 ExecuteNonQuery,大概率触发 SQLITE_BUSY 或直接抛 InvalidOperationException。
- 每个线程/请求都应新建自己的
SQLiteConnection,用完立刻Dispose()(推荐using) - 连接字符串里加
Cache=Shared可提升多连接场景下的性能,但不能解决并发写冲突 - 真有高频并发写需求(比如日志),考虑加一层内存队列 + 单线程写入器,或者换用 WAL 模式(需在建库后执行
PRAGMA journal_mode=WAL;)
SQLite 的轻量优势建立在“单写多读”假设上,强行压测并发写,很快就会撞到锁等待和磁盘 I/O 瓶颈——这时候该想的不是怎么调参数,而是数据是否真的适合放本地文件里。


















