【问题标题】:C# SQLite, database being left locked after a readC# SQLite,数据库在读取后被锁定
【发布时间】:2015-05-06 10:41:30
【问题描述】:

我已经阅读了一些有关此的相关帖子,但不太了解。正在发生的事情似乎是在对数据库的访问之后,数据库被锁定,以便可以读取,但不能写入。退出应用程序后,数据库再次解锁。你能不能看着我像无知一样跟我说话,指出我处理这个问题的方式的错误?

 public static Partner GetOnePartner(string code)
 {
    Partner partner = new Partner();
    SQLiteConnection connection = GroomwatchDB.GetConnection();
    string sqlStatement = "SELECT * FROM partners WHERE partner_code = @partner_code";

    SQLiteCommand command = new SQLiteCommand(sqlStatement, connection);
    command.Parameters.Add(new SQLiteParameter("@partner_code"));
    command.Parameters["@partner_code"].Value = code;

    try
    {
        connection.Open();
        SQLiteDataReader reader = command.ExecuteReader(CommandBehavior.SingleRow);
        if(reader.Read())
        {
            partner.Code = reader["partner_code"].ToString();
            partner.Last_name = reader["last_name"].ToString();
            partner.First_name = reader["first_name"].ToString();
            partner.Pay_rate = (double)reader["pay_rate"];
            partner.Active = reader["active"].ToString();
        }
        else
        {
            partner.Code = code;
            partner.Last_name = "Not Found";
        }

    }
    catch (SQLiteException ex)
    {
       throw ex;
    }
    finally
    {
        connection.Close();
    }

    return partner;

} 

【问题讨论】:

  • 当我不得不猜测时:在 else 分支之后尝试 reader.Close()。至少它不会变得更糟。
  • 如果 SQLiteDataReader、SQLiteCommand 或 SQLiteConnection 实现了 IDisposable 接口,您可以使用 using 语句确保它们被释放。
  • 连接字符串是什么?您是否使用预写日志记录? GetConnection 方法有什么作用?
  • 您是否尝试从不同的线程访问数据库?你使用交易吗? SQLite 允许多个阅读器,但只有一个编写器,这可能意味着您打开了一个连接以便在某处进行写入
  • 请使用using来处理所有个一次性对象——连接、命令和阅读器。

标签: c# sqlite locked


【解决方案1】:

您应该使用IDisposable 模式正确使用您的连接。

实际上,每个实现IDisposable 接口的类都需要使用 using 来调用。这确保了方法 Dispose() 被调用,因此非托管资源被清除(并且您不会以打开的文件结束):

public static Partner GetOnePartner(string code)
 {
    Partner partner = new Partner();
    string sqlStatement = "SELECT * FROM partners WHERE partner_code = @partner_code";
    using(SQLiteConnection connection = GroomwatchDB.GetConnection())
    using(SQLiteCommand command = new SQLiteCommand(sqlStatement, connection))
    {
        command.Parameters.Add(new SQLiteParameter("@partner_code"));
        command.Parameters["@partner_code"].Value = code;
        connection.Open();
        using(SQLiteDataReader reader = command.ExecuteReader(CommandBehavior.SingleRow))
        {
            if(reader.Read())
            {
                partner.Code = reader["partner_code"].ToString();
                partner.Last_name = reader["last_name"].ToString();
                partner.First_name = reader["first_name"].ToString();
                partner.Pay_rate = (double)reader["pay_rate"];
                partner.Active = reader["active"].ToString();
            }
            else
            {
                partner.Code = code;
                partner.Last_name = "Not Found";
            }
        }
    }
    return partner;
} 

参考文献:

【讨论】:

  • 既然他在finally 部分关闭了连接,这种改变真的有助于解决他的问题吗?请注意,我知道他进入try/finally 块之前的异常实际上会使数据库连接保持打开状态,但由于他没有说它正在崩溃,我假设代码运行完成。换句话说,我完全同意像你展示的那样切换到IDisposable 模式,我只是不确定这是否有助于解决他的问题,假设问题确实出在发布的代码中。
  • 或许能解决问题。作为“我必须处理 SQLiteCommand 对象吗?”中的评论。显示,忘记释放 SQLiteCommand 会导致发布者出现问题,即使连接已释放。
  • @Cyril Gandon,我现在已经阅读了有关在这种情况下“使用”的信息。我的书都没有提到它。谢谢你。这似乎是有道理的。一旦对象超出范围并释放其资源(连接等),它就会处理该对象。在获得所有适当的时间来使用它之前,我必须了解更多信息,但我对这种情况有所了解。我今晚会试试,然后回来报告。在您的代码中,您不会关闭连接。我不应该打电话给 Close() 吗?
  • 这就是它的美妙之处,好的 IDisposable 对象 在它们的 Dispose() 方法中关闭它们自己(请注意,当您点击闭合大括号时会调用 Dispose() 方法)。参见例如stackoverflow.com/questions/630955/…
  • @Cyril Gandon -- 我必须道歉。除了一组缺少括号外,您的解决方案是正确的。我在实现它时又犯了一个错误。当我回头看时,这很明显。现在它不会将其锁定。谢谢一百万!
猜你喜欢
  • 1970-01-01
  • 2020-01-31
  • 2011-08-05
  • 2011-10-30
  • 1970-01-01
  • 1970-01-01
  • 2021-11-20
  • 2015-05-11
相关资源
最近更新 更多