SQLite插入未提交引发异常:索引是否损坏及提交语法咨询
问题描述
我正在开发一款用于天文摄影的个人C# Windows Form工具应用,此前多次从仓库恢复代码,SQLite数据库已受损,怀疑索引出现问题(可重建数据库)。
代码逻辑为先查询数据库中是否已记录目标,再执行插入操作。
查询代码
string connectionString = "Data Source=..\\..\\Astrophotography DataBase\\Astrophotography.db;Version=3;"; public bool QueryATI(string strTargetName, string[] arrEquipment) { using (SQLiteConnection conn = new SQLiteConnection(connectionString)) { conn.Open(); bool result = false; SQLiteCommand command = new SQLiteCommand("SELECT ATI_TargetName, ATI_Telescope_Lens_Used FROM Astro_Target_Imaged WHERE ATI_TargetName = @Target", conn); command.Parameters.Add(new SQLiteParameter("@Target", strTargetName)); using (SQLiteDataReader TargetReader = command.ExecuteReader()) { int i = 0; if (TargetReader.HasRows) { // It is very possible a target has been imaged more than once with different // equipment or focal lengths. This checks to see what has been recorded of // any of them, and if this one is not recorded. It will be added. { string strTelescope = TargetReader["ATI_Telescope_Lens_Used"].ToString(); string strArrayValue = arrEquipment[i].ToString(); if (strTelescope == arrEquipment[i]) { result = true; conn.Clone(); return result; } i++; } } result = false; conn.Clone(); return result; } result = false; conn.Clone(); return result; } }
插入代码
public void BuildATI(string strTargetName, string strMount, string strICamera, string strTelescope, string strFilter, string strGuidCamera, string strGuideScope) { using (SQLiteConnection conn = new SQLiteConnection(connectionString)) { conn.Open(); bool result = false; string strInsert = ("INSERT INTO Astro_Target_Imaged"); string strColumns = "(ATI_TargetName, ATI_Mount_Used, ATI_Image_Camera, ATI_Telescope_Lens_Used, ATI_Filter, ATI_Guide_Camera, ATI_Guide_Scope_Used)"; string strValues = "VALUES (@Target, @Mount, @ICamera, @Telescope, @Filter, @GCamera, @GScope)"; string strQuery = strInsert + strColumns + strValues; SQLiteCommand command = new SQLiteCommand(strQuery, conn); command.Parameters.Add(new SQLiteParameter("@Target", strTargetName)); command.Parameters.Add(new SQLiteParameter("@Mount", strMount)); command.Parameters.Add(new SQLiteParameter("@ICamera", strICamera)); command.Parameters.Add(new SQLiteParameter("@Telescope", strTelescope)); command.Parameters.Add(new SQLiteParameter("@Filter", strFilter)); command.Parameters.Add(new SQLiteParameter("@GCamera", strGuidCamera)); command.Parameters.Add(new SQLiteParameter("@GScope", strGuideScope)); //.FirstOrDefault(); try { command.ExecuteNonQuery(); //conn.Commit(); } catch (Exception ex) { throw new Exception(ex.Message); } conn.Clone(); } }
问题现象
插入操作无报错,但在SQLiteStudio中查询不到数据;再次运行相同数据时,查询代码判断存在行,但访问列时抛出“无行”异常,怀疑数据库索引损坏。
现咨询:
- 数据库索引是否已损坏?
- SQLite的提交语句语法是什么?
解答
一、数据库索引是否损坏?
目前的现象更可能是代码逻辑错误导致的,而非索引损坏,但也不能完全排除数据库损坏的可能,先优先排查代码问题:
代码中的关键错误
conn.Clone()误用:所有出现conn.Clone()的地方都应该是conn.Close(),Clone()是创建连接副本的方法,不是关闭连接。未正确关闭连接可能导致事务未正常提交,数据无法持久化到磁盘。- DataReader 未正确读取行:
QueryATI方法中,TargetReader.HasRows为真时,未调用TargetReader.Read()移动到有效行就直接访问列,这会直接抛出“无行”异常;同时代码只尝试检查一次,没有循环遍历所有匹配的行来对比设备数组。 - 路径与连接释放问题:
using块会自动释放连接,无需显式调用Close(),但错误的Clone()操作可能干扰连接的正常释放流程;另外要确认连接字符串中的数据库路径是否正确,避免写入到非预期的目录(比如调试和发布环境的路径差异)。
排查数据库损坏的方法
如果修正代码后问题仍存在,可执行以下操作验证:
- 使用SQLite命令行工具执行
PRAGMA integrity_check;,检查数据库完整性。 - 重建数据库:将现有数据导出为SQL脚本,创建新数据库后导入脚本。
二、SQLite的提交语句语法
SQLite 默认开启自动提交(AutoCommit),执行 INSERT/UPDATE/DELETE 后会自动提交事务。如果手动开启了事务(使用 BEGIN TRANSACTION;),需要手动提交,语法为:
COMMIT;
若需要回滚事务则使用:
ROLLBACK;
在C#代码中手动控制事务的示例:
using (SQLiteConnection conn = new SQLiteConnection(connectionString)) { conn.Open(); using (SQLiteTransaction tran = conn.BeginTransaction()) { try { SQLiteCommand command = new SQLiteCommand(insertQuery, conn, tran); command.ExecuteNonQuery(); tran.Commit(); // 手动提交事务 } catch (Exception ex) { tran.Rollback(); // 出错时回滚 throw ex; } } }
代码修正建议
- 替换所有
conn.Clone()为conn.Close(),或者直接删除这些调用(using块会自动释放连接)。 - 修正
QueryATI中的DataReader读取逻辑:
if (TargetReader.HasRows) { while (TargetReader.Read()) // 循环读取所有匹配行 { string strTelescope = TargetReader["ATI_Telescope_Lens_Used"].ToString(); foreach (string equip in arrEquipment) // 遍历设备数组对比 { if (strTelescope == equip) { result = true; return result; } } } }
内容的提问来源于stack exchange,提问作者OldAndRetired
相关产品推荐
相关产品推荐

