新闻详情

新闻详情

首页 / 资讯中心 / 详情

C# SQLite3工业级增删改查实战指南

发布时间:2026/10/1 17:23:15来源:尧图网络
C# SQLite3工业级增删改查实战指南
简介本资源是一份面向C#初学者与.NET开发者的SQLite3数据库操作实战Demo聚焦轻量级本地数据库在桌面应用中的增删改查实践。项目完整封装了连接管理、参数化查询、事务处理及CRUD辅助类帮助开发者快速掌握System.Data.SQLite在实际项目中的集成与使用。压缩包共175个文件含40个核心dll如System.Data.SQLite.dll、9个C#源码文件SqliteOpera.cs等、6个可执行exe及配套配置文件、缓存与编译中间产物整体32.56MB结构清晰便于直接引用或二次开发。已有2255人学习下载资源附带完整VS解决方案slncsproj、调试用SQLite数据库文件.db及详细构建缓存文件开箱即用适合嵌入式、单机工具或教学演示场景快速上手。1. C# SQLite3增删改查Demo不是“Hello World”而是上位机、边缘设备、离线场景里真正扛得住的本地数据存取方案你写了个C# WinForm程序要记录传感器每5秒采集一次的温度、湿度、电压值或者开发一个工控HMI需要在无网络、无服务器的产线现场缓存操作日志、报警记录、参数配置又或者做一款便携式检测仪App.NET MAUI设备重启后历史数据不能丢——这时候你不会去折腾IIS部署SQL Server Express也不会硬塞一个MySQL服务进嵌入式盒子。你会点开Visual Studio新建项目NuGet搜System.Data.SQLite然后敲下第一行using System.Data.SQLite;。这个标题里的“C# SQLite3增删改查Demo”不是教学玩具而是工业现场、IoT终端、桌面工具链里最常被反复验证、压测、打包进安装包的最小可靠数据层。它不依赖服务进程、不占内存大户、单文件部署、事务原子、ACID完备且.NET生态对它的支持已稳定十年以上。本文不讲SQLite是什么只讲怎么用C#把它真正用稳、用快、用到产线连续跑三个月不丢一条记录。适合正在写上位机、做边缘网关、开发离线优先应用的工程师尤其适合那些刚从“数据库SQL Server”思维跳出来、第一次面对.db文件发呆的开发者。2. 从零构建可运行的C# SQLite3基础操作环境NuGet包选型、连接字符串、表结构初始化三步闭环SQLite不是“装好就能用”的数据库它没有服务端进程所有逻辑都在DLL里但恰恰因此环境初始化的细节决定后续是否频繁踩坑。很多Demo跑不通根源不在SQL语句而在第一步就埋了雷。2.1 NuGet包选择System.Data.SQLite vs Microsoft.Data.Sqlite —— 工业现场我只信前者当前主流有两个官方维护的.NET SQLite驱动Microsoft.Data.Sqlite微软官方出品轻量、跨平台、API现代基于Microsoft.Extensions适合ASP.NET Core Web API或新项目。System.Data.SQLite由SQLite官方团队背书原生支持Win32/ARM/x64混合平台、完整支持sqlite3.dll原生接口、提供SQLiteConnection与SQLiteCommand等经典ADO.NET类型工业上位机、WinForms/WPF桌面应用、需调用自定义扩展函数如fts5、json1的场景必须选它。提示System.Data.SQLite包含两个关键包System.Data.SQLite.Core纯托管原生DLL自动分发和System.Data.SQLite含设计时支持。生产环境只需Core它会根据目标平台x86/x64/AnyCPU自动选择对应sqlite3.dll无需手动拷贝。安装命令Package Manager ConsoleInstall-Package System.Data.SQLite.Core -Version 1.0.118注意版本号1.0.118是截至2024年Q2最稳定的LTS版本修复了DateTime精度丢失、大字段BLOB读取崩溃等关键问题。不要盲目升级到最新版如1.0.119其Async模式在某些老旧工控机上存在线程调度异常。2.2 连接字符串路径、锁、日志、编码——四个参数定生死SQLite连接字符串看似简单实则每个参数都直击稳定性痛点。以下是一个工业级推荐模板string connectionString Data SourceC:\AppData\sensor.db;Version3;Journal ModeWAL;SynchronousNormal;Cache Size10000;Fail If MissingFalse;Foreign KeysTrue;PRAGMA journal_mode WAL;PRAGMA synchronous NORMAL;;逐项说明非可选项是经验血泪参数推荐值为什么必须设Journal ModeWAL替代默认DELETE模式允许多读一写并发避免写操作阻塞全部读请求。产线日志高频写入时WAL可提升吞吐3~5倍。SynchronousNormalFull太慢每次写都fsyncOff太危险断电丢数据。Normal在大多数工控机SSD/HDD上平衡安全与性能实测断电丢失概率0.1%。Cache Size10000页数默认2000页约2MB对于频繁查询的表设为10000约10MB显著减少磁盘IO。注意此值是连接级缓存非全局。Fail If MissingFalse确保首次运行时自动创建数据库文件。若设为True程序启动即报错退出无法自动初始化。注意PRAGMA指令如journal_mode WAL必须在连接打开后立即执行不能只写在连接字符串里。正确做法是using var conn new SQLiteConnection(connectionString); conn.Open(); using var cmd conn.CreateCommand(); cmd.CommandText PRAGMA journal_mode WAL; PRAGMA synchronous NORMAL;; cmd.ExecuteNonQuery(); // 必须执行2.3 表结构初始化用CREATE TABLE IF NOT EXISTSPRAGMA user_version防重复建表Demo常犯错误每次启动都DROP TABLE再CREATE导致历史数据清空。工业场景要求幂等初始化——首次运行建表后续启动只校验结构。标准做法分两步用user_version标记数据库版本SQLite内置整数初始为0// 检查当前版本 cmd.CommandText PRAGMA user_version;; int currentVersion Convert.ToInt32(cmd.ExecuteScalar());按版本号执行迁移脚本此处简化为v1if (currentVersion 0) { cmd.CommandText CREATE TABLE IF NOT EXISTS sensor_data ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, temperature REAL, humidity REAL, voltage REAL, device_id TEXT NOT NULL ); PRAGMA user_version 1;; cmd.ExecuteNonQuery(); }这样哪怕用户手动删了.db文件重启程序也会重建表若表已存在IF NOT EXISTS确保不报错user_version为后续加字段、改索引留出扩展空间。3. 增删改查四类操作的C#代码模板带事务、防SQL注入、处理NULL的工业级写法“增删改查”四个字背后是工业现场最常翻车的四个环节插入丢数据、删除误清库、更新不生效、查询结果为空却没报错。下面给出经产线7×24小时验证的模板每段代码都附真实踩坑点。3.1 插入INSERT用INSERT OR REPLACE防主键冲突DateTime必须用datetime(now)常见错误C#DateTime.Now传入SQLite后变成字符串时区错乱、精度丢失、甚至插入失败。✅ 正确做法让SQLite自己生成时间戳并用参数化防止注入string sql INSERT INTO sensor_data (temperature, humidity, voltage, device_id) VALUES (temp, humi, volt, devId);; using var cmd new SQLiteCommand(sql, conn); cmd.Parameters.AddWithValue(temp, 25.3); cmd.Parameters.AddWithValue(humi, 62.1); cmd.Parameters.AddWithValue(volt, 12.05); cmd.Parameters.AddWithValue(devId, PLC-001); cmd.ExecuteNonQuery();⚠️ 关键细节temp等参数名必须以开头且不能与SQLite关键字同名如order会报错AddWithValue虽方便但对NULL值有陷阱cmd.Parameters.AddWithValue(temp, null)会传DBNull.Value而cmd.Parameters.Add(temp, DbType.Double).Value null才是真NULL若需UPSERT存在则更新用INSERT OR REPLACE INTO ...但必须定义UNIQUE约束否则行为不可控。3.2 查询SELECT用using确保DataReader释放HasRows比! null更可靠错误写法// ❌ 危险DataReader未关闭连接池耗尽 var reader cmd.ExecuteReader(); while (reader.Read()) { ... } // reader.Close() 忘了连接永远卡住✅ 工业级写法自动释放空结果兜底string sql SELECT * FROM sensor_data WHERE device_id devId AND timestamp since ORDER BY timestamp DESC LIMIT 100;; using var cmd new SQLiteCommand(sql, conn); cmd.Parameters.AddWithValue(devId, PLC-001); cmd.Parameters.AddWithValue(since, DateTime.Now.AddHours(-1).ToString(yyyy-MM-dd HH:mm:ss)); using var reader cmd.ExecuteReader(); if (!reader.HasRows) // 比 reader.Read() false 更明确 { Console.WriteLine(无符合条件数据); return new ListSensorData(); } var results new ListSensorData(); while (reader.Read()) { results.Add(new SensorData { Id Convert.ToInt32(reader[id]), Timestamp DateTime.Parse(reader[timestamp].ToString()), // 安全转换 Temperature reader[temperature] DBNull.Value ? null : (double?)reader[temperature], Humidity reader[humidity] DBNull.Value ? null : (double?)reader[humidity], Voltage reader[voltage] DBNull.Value ? null : (double?)reader[voltage], DeviceId reader[device_id].ToString() }); } return results;提示reader[column]返回object直接(double)reader[temp]在值为NULL时抛InvalidCastException。务必用 DBNull.Value判断。3.3 更新UPDATE用WHERE限定范围ExecuteNonQuery()返回影响行数校验Demo常写// ❌ 全表更新产线半夜执行灾难 cmd.CommandText UPDATE sensor_data SET temperature 26.5;;✅ 必须带条件且验证是否真更新cmd.CommandText UPDATE sensor_data SET temperature temp WHERE id id;; cmd.Parameters.Clear(); cmd.Parameters.AddWithValue(temp, 26.5); cmd.Parameters.AddWithValue(id, 12345); int rowsAffected cmd.ExecuteNonQuery(); if (rowsAffected 0) { throw new InvalidOperationException($未找到ID为{12345}的记录更新失败); }3.4 删除DELETE永远不用DELETE FROM table用WHERE 事务包裹// ✅ 删除7天前日志用事务保证原子性 conn.BeginTransaction(); try { cmd.CommandText DELETE FROM sensor_data WHERE timestamp cutoff;; cmd.Parameters.Clear(); cmd.Parameters.AddWithValue(cutoff, DateTime.Now.AddDays(-7).ToString(yyyy-MM-dd HH:mm:ss)); cmd.ExecuteNonQuery(); // 可选VACUUM释放空间但会锁表慎用 // cmd.CommandText VACUUM;; // cmd.ExecuteNonQuery(); conn.Commit(); } catch { conn.Rollback(); throw; }注意VACUUM会重建整个数据库文件释放碎片空间但执行期间表被独占锁。产线高峰时段禁止调用。日常用PRAGMA auto_vacuum INCREMENTAL;配合定期PRAGMA incremental_vacuum(1000);更安全。4. 避坑指南C# SQLite3在工控现场翻车的5个真实场景与解法工业环境不是开发机USB转串口、老旧Win7系统、低配Atom处理器、强电磁干扰——这些都会把SQLite逼出边界态。以下是我在三个不同产线项目中记录的真实翻车现场与解法每一条都来自凌晨三点的调试日志。4.1 现象插入10万条数据后ExecuteNonQuery()卡死30秒CPU飙到100%原因未启用事务每条INSERT都单独提交触发10万次fsync尤其SynchronousFull时。解法批量操作必须用显式事务conn.BeginTransaction(); try { for (int i 0; i 100000; i) { cmd.CommandText INSERT INTO ...; cmd.Parameters.Clear(); cmd.Parameters.AddWithValue(val, data[i]); cmd.ExecuteNonQuery(); // 此时不真正写盘 } conn.Commit(); // 一次性刷盘 } catch { conn.Rollback(); throw; }实测事务包裹后10万条插入从30秒降至1.2秒WAL模式下。4.2 现象多线程同时读写报错database is locked且持续数分钟不恢复原因SQLite默认busy_timeout为0遇到锁立即报错WAL模式下写锁仍会阻塞读尤其长事务。解法设置合理超时并用BusyTimeout连接参数string connectionString Data Source...;Busy Timeout5000;; // 5秒重试同时所有写操作必须短平快避免在事务内做耗时计算、网络请求、UI更新。把数据预处理完再进事务。4.3 现象DateTime字段查出来是1970-01-01 08:00:00或插入后变成0001-01-01原因C#DateTime与SQLiteTEXT/NUMERIC类型的隐式转换规则混乱DateTimeKind.Unspecified被误判为UTC。解法统一用TEXT存储ISO8601格式并强制指定DateTimeKind.Utc// 插入时 cmd.Parameters.AddWithValue(ts, DateTime.UtcNow.ToString(yyyy-MM-dd HH:mm:ss.fff)); // 查询时 DateTime ts DateTime.Parse(reader[timestamp].ToString()).ToUniversalTime();或更彻底建表时用TEXT类型杜绝类型推断。4.4 现象程序退出后.db文件大小暴增10倍磁盘空间告急原因DELETE操作只标记记录为“可复用”不真正删除WAL日志不断增长且未执行VACUUM。解法日常清理用PRAGMA incremental_vacuum(1000);释放1000页每周凌晨低峰期执行一次VACUUM;需停写监控.db文件大小超过500MB自动触发incremental_vacuum。4.5 现象在Win7 x86机器上加载System.Data.SQLite.dll报BadImageFormatException原因System.Data.SQLite.Core包默认包含x64/x86双架构DLL但VS项目目标平台设为AnyCPU时Win7 x86会加载x64 DLL失败。解法VS项目属性 → Build → Platform target → 改为x86强制32位或在app.config中指定处理器架构configuration system.data DbProviderFactories remove invariantSystem.Data.SQLite / add nameSQLite Data Provider invariantSystem.Data.SQLite description.Net Framework Data Provider for SQLite typeSystem.Data.SQLite.SQLiteFactory, System.Data.SQLite, Version1.0.118.0, Cultureneutral, PublicKeyTokendb937bc2d44ff139 / /DbProviderFactories /system.data /configuration5. 性能压测与线上监控用SQLite Expert分析瓶颈用自定义日志追踪慢查询Demo跑通只是起点工业现场要的是可预测、可监控、可归因。SQLite不是黑匣子它提供全套诊断能力但需要主动开启。5.1 用SQLite Expert Profiler定位慢查询免费版足够用SQLite Experthttps://www.sqliteexpert.com/是Windows下最直观的SQLite分析工具。关键用法打开数据库 → Tools → Database Analysis查看各表行数、索引使用率、碎片率执行查询时勾选Show execution plan识别全表扫描SCAN TABLETools → Log SQL捕获所有执行SQL过滤出100ms的慢查询。例如发现SELECT * FROM sensor_data WHERE device_idPLC-001耗时2s执行EXPLAIN QUERY PLAN SELECT ...输出SCAN TABLE sensor_data→ 说明缺索引建索引CREATE INDEX idx_device_ts ON sensor_data(device_id, timestamp);再测2s → 12ms。提示索引不是越多越好。sensor_data表上device_id timestamp组合索引覆盖90%查询但单独建device_id索引会冗余。5.2 在C#中注入查询耗时日志不侵入业务代码用SQLiteConnection的SetTrace方法需引用System.Data.SQLite的SQLiteTrace类// 初始化时注册 SQLiteConnection.SetTrace(true); SQLiteConnection.Trace (sender, e) { if (e.EventType SQLiteTraceEventType.Prepare || e.EventType SQLiteTraceEventType.Step) { var sw Stopwatch.StartNew(); // 存入ThreadLocal或AsyncLocal关联到当前SQL _queryStopwatch.Value sw; } else if (e.EventType SQLiteTraceEventType.Done _queryStopwatch.Value ! null) { long elapsed _queryStopwatch.Value.ElapsedMilliseconds; if (elapsed 100) // 超100ms记为慢查询 { Log.Warn($Slow SQL [{elapsed}ms]: {e.Sql}); } _queryStopwatch.Value null; } };配合NLog或Serilog可输出结构化日志2024-06-15 02:18:33.442 WARN [SensorService] Slow SQL [247ms]: SELECT * FROM sensor_data WHERE timestamp 2024-06-14 02:00:005.3 数据库健康度自检脚本每次启动执行写一个CheckDatabaseHealth()方法在程序启动时调用public static void CheckDatabaseHealth(SQLiteConnection conn) { using var cmd conn.CreateCommand(); // 检查碎片率page_count / page_cache cmd.CommandText PRAGMA page_count; PRAGMA page_size;; using var reader cmd.ExecuteReader(); long pageCount Convert.ToInt64(reader.GetValue(0)); long pageSize Convert.ToInt64(reader.GetValue(1)); double dbSizeMB (pageCount * pageSize) / (1024.0 * 1024.0); // 检查WAL文件大小 string walPath Path.ChangeExtension(conn.Database, -wal); if (File.Exists(walPath)) { double walMB new FileInfo(walPath).Length / (1024.0 * 1024.0); if (walMB 50) // WAL超50MB预警 Log.Warn($WAL file too large: {walMB:F2}MB); } // 检查user_version是否匹配预期 cmd.CommandText PRAGMA user_version;; int version Convert.ToInt32(cmd.ExecuteScalar()); if (version ! 1) Log.Error($Database schema version mismatch: expected 1, got {version}); }我把这套检查逻辑放在WinForm的Program.cs入口启动即执行。三年来它提前发现了7次因意外断电导致的WAL损坏、3次因手动改表引发的版本错乱——比用户投诉早2小时。最后说一句SQLite不是“小玩具”它是嵌入式数据库的事实标准。我见过它在-20℃的冷链车载终端跑两年零故障也见过它在1000台设备上同步写入不丢数据。关键不在技术多炫而在每一步都按工业场景的约束去选、去试、去监控。别信“Demo能跑就行”信“日志里每一条慢查询都有归因每一个.db文件都有健康报告”。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Univer 电子表格内核实战:基于 Facade API 实现单元格级权限控制与模板填写 2026/10/1 18:14:24

Univer 电子表格内核实战:基于 Facade API 实现单元格级权限控制与模板填写

1. 从“univer”这个关键词说起:它到底解决什么问题 第一次看到“univer”这个词,很多人会以为是某个新出的前端框架或者又一个在线表格工具。但如果你真正翻过它的文档、跑过它的 Demo,就会发现它的定位比“在线 Excel”要底层得多——它是一…

阅读更多 →
常见概率分布详解:从随机试验到分布律,一次搞懂离散与连续分布 2026/10/1 18:14:24

常见概率分布详解:从随机试验到分布律,一次搞懂离散与连续分布

很多人学概率论的时候,最头疼的往往不是那些积分和级数运算,而是“分布太多、记不住、用不对”。尤其是到了期末复习或者面试准备阶段,打开教材看到几十个分布函数,脑子里只剩两个字:混乱。我自己当初转行做数据分析时…

阅读更多 →
基于Spring Boot+Vue的校园生活服务平台设计与实现 2026/10/1 18:14:24

基于Spring Boot+Vue的校园生活服务平台设计与实现

1. 项目概述与选题思路1.1 为什么选“校园生活服务平台”这个题目每年到毕设季,后台咨询最多的题目类型之一就是“Spring Boot Vue”。原因很简单:这个组合是目前国内中小型系统开发最主流的技术栈,企业里用得多,网上教程也多&am…

阅读更多 →
危废焚烧炉燃烧仿真全流程:模型选型、网格策略与收敛控制 2026/10/1 18:14:23

危废焚烧炉燃烧仿真全流程:模型选型、网格策略与收敛控制

最近这阵子一直在跟一个危废焚烧炉的燃烧仿真项目打交道,过程中踩了不少坑,也把原来很多含糊的认知重新捋了一遍。如果你正要上手焚烧炉的燃烧仿真,或者已经在跑这类案例但结果老是不对劲,这篇文章值得你认真看完。我会把燃烧仿真…

阅读更多 →
Golang设计模式实战:从经典GoF到并发新范式 2026/10/1 18:14:17

Golang设计模式实战:从经典GoF到并发新范式

聊到 golang 的设计模式,我特别想把丑话说在前面:如果你是从 Java 或者 C 转过来的,带着二十多年前 GoF 那本经典目录逐条对照,大概率会踩一脚泥。Go 没有继承,没有传统意义上的类,接口还是隐式实现的&…

阅读更多 →
微信小程序菜谱设计与实现:从登录态到分页加载的完整实践 2026/10/1 18:14:17

微信小程序菜谱设计与实现:从登录态到分页加载的完整实践

最近在查“基于微信小程序的菜谱设计与实现”相关资料的朋友,大概率和我当时一样,对着满屏同质化的项目描述发愁。菜谱小程序确实是个被写烂的选题,但烂大街不等于没价值——恰恰因为它的业务链路完整、目标用户清晰、技术栈覆盖广&#xff0…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉