You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中SQLite数据库锁定异常排查:已尝试方案仍未解决

解决SQLite数据库锁定异常的问题

嘿,我帮你找到了几个导致SQLite数据库锁定的关键问题,咱们一步步拆解并修复:

1. 别再用MultipleActiveResultSets=True了!

这个参数是SQL Server专属的特性,SQLite完全不支持它——你加在连接字符串里不仅没用,反而可能干扰连接的正常行为,直接删掉就好。

2. 类级别的连接对象是大坑(核心问题)

你在AdminForm里定义了全局的ObservationDBConnection,然后在构造函数里打开又关闭,后续SaveButton_Click再复用这个连接。但SQLite是文件型数据库,同一时间只能有一个写入连接,一旦连接因为异常没被正确释放(比如Close()没执行到),就会直接锁死数据库。

正确做法:永远不要复用连接对象,每次操作数据库时,用using语句创建新连接——using会自动帮你释放连接(哪怕代码抛出异常),这是数据库操作的标准最佳实践。

3. 忘了关闭DataReader?它会占着连接不放

你的代码里很多SQLiteDataReader都没调用Close(),也没包在using里。DataReader会保持连接处于占用状态,直到被关闭,这也是导致锁定的常见原因。

4. 紧急提醒:你的代码有严重的SQL注入风险

所有直接拼接用户输入的SQL语句(比如VALUES ('" + originatorName + "', ...))都是高危操作——不仅会导致SQL语法错误(比如用户输入里有单引号),还会被黑客利用注入恶意代码。必须改用参数化查询。


修复后的示例代码

1. 插入Originator的正确写法

// 去掉无用的MARS参数
string connectionString = @"Data Source=D:\CCIW\LCM\Organisational Database\OrganisationalDB;";
using (SQLiteConnection originatorDBConnection = new SQLiteConnection(connectionString))
{
    originatorDBConnection.Open();
    // 用参数占位符代替直接拼接
    string originatorINSERT = @"INSERT INTO Originator (Name, Organisation, Address, CellphoneNumber, TelephoneNumber, Email) 
                                VALUES (@Name, @Organisation, @Address, @CellphoneNumber, @TelephoneNumber, @Email);";
    using (SQLiteCommand originatorCommand = new SQLiteCommand(originatorINSERT, originatorDBConnection))
    {
        // 添加参数,既防注入又避免语法错误
        originatorCommand.Parameters.AddWithValue("@Name", originatorNameTextBox.Text);
        originatorCommand.Parameters.AddWithValue("@Organisation", originatorOrganisationTextBox.Text);
        originatorCommand.Parameters.AddWithValue("@Address", originatorAddressRichTextBox.Text);
        originatorCommand.Parameters.AddWithValue("@CellphoneNumber", originatorCellTextBox.Text);
        originatorCommand.Parameters.AddWithValue("@TelephoneNumber", originatorTelTextBox.Text);
        originatorCommand.Parameters.AddWithValue("@Email", originatorEmailTextBox.Text);
        
        originatorCommand.ExecuteNonQuery();
    }
    // 不需要手动Close(),using会自动处理连接释放
}

2. AdminForm构造函数的修复版

public AdminForm()
{
    InitializeComponent();
    
    string connectionString = @"Data Source=D:\CCIW\LCM\Organisational Database\OrganisationalDB;";
    // 用using包裹连接,确保自动释放
    using (SQLiteConnection observationDBConnection = new SQLiteConnection(connectionString))
    {
        observationDBConnection.Open();
        
        // 查询Originator,用using包裹DataReader自动关闭
        string originatorSELECT = "SELECT * FROM Originator;";
        using (SQLiteCommand command = new SQLiteCommand(originatorSELECT, observationDBConnection))
        using (SQLiteDataReader reader = command.ExecuteReader())
        {
            List<string> originatorNames = new List<string>();
            while (reader.Read())
            {
                originatorNames.Add(Convert.ToString(reader["Name"]));
            }
            OriginatorNameComboBox.DataSource = originatorNames;
        }
        
        // 查询ECP的逻辑同理
        string ecpNumberSELECT = "SELECT * FROM ECP";
        using (SQLiteCommand command2 = new SQLiteCommand(ecpNumberSELECT, observationDBConnection))
        using (SQLiteDataReader reader2 = command2.ExecuteReader())
        {
            List<string> ecpNumbers = new List<string>();
            while (reader2.Read())
            {
                ecpNumbers.Add(Convert.ToString(reader2["Number"]));
            }
            ECPNumComboBox.DataSource = ecpNumbers;
        }
        
        // 填充TC Decision下拉框的逻辑不变
        List<string> tcDecision = new List<string>();
        tcDecision.Add("Rework");
        tcDecision.Add("Reject");
        tcDecision.Add("Approve");
        TCDecisionComboBox.DataSource = tcDecision;
    }
}

3. SaveButton_Click的修复片段

private void SaveButton_Click(object sender, EventArgs e)
{
    string connectionString = @"Data Source=D:\CCIW\LCM\Organisational Database\OrganisationalDB;";
    using (SQLiteConnection observationDBConnection = new SQLiteConnection(connectionString))
    {
        observationDBConnection.Open();
        
        // 参数化插入ImpactType
        string impactTypeINSERT = @"INSERT INTO ImpactType (ImpactType, Description) 
                                    VALUES (@ImpactType, @Description);";
        using (SQLiteCommand impactTypeCommand = new SQLiteCommand(impactTypeINSERT, observationDBConnection))
        {
            impactTypeCommand.Parameters.AddWithValue("@ImpactType", impactType);
            impactTypeCommand.Parameters.AddWithValue("@Description", impactDescription);
            impactTypeCommand.ExecuteNonQuery();
        }
        
        // 修复你之前的笔误:ExecuteReader用错了命令对象
        string tcDecisionINSERT = @"INSERT INTO TCDecision (Decision, Description) 
                                    VALUES (@Decision, @Description);";
        using (SQLiteCommand tcDecisionCommand = new SQLiteCommand(tcDecisionINSERT, observationDBConnection))
        {
            tcDecisionCommand.Parameters.AddWithValue("@Decision", TechnicalCommitteeDecision);
            tcDecisionCommand.Parameters.AddWithValue("@Description", TechnicalCommitteeDescription);
            tcDecisionCommand.ExecuteNonQuery();
        }
        
        // 其他插入/查询逻辑都照这个模式:用using包裹命令和DataReader,用参数化查询
        
        // 示例:参数化查询OriginatorID
        string originatorIDSELECT = @"SELECT ID FROM Originator WHERE Name=@Name;";
        using (SQLiteCommand originatorIDCommand = new SQLiteCommand(originatorIDSELECT, observationDBConnection))
        {
            originatorIDCommand.Parameters.AddWithValue("@Name", OriginatorNameComboBox.Text);
            using (SQLiteDataReader originatorIDReader = originatorIDCommand.ExecuteReader())
            {
                // 先判断是否有结果再取值,避免空引用
                if (originatorIDReader.Read())
                {
                    originatorIDOBS = originatorIDReader.GetInt32(0);
                }
            }
        }
    }
}

额外排查小技巧

  • 检查有没有其他程序(比如SQLite管理工具)正在打开这个数据库文件,有的话关掉它;
  • 确保你用的是最新版本的SQLite库,旧版本可能存在锁定相关的bug。

内容的提问来源于stack exchange,提问作者Zenadia Groenewald

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:23:00