SQLite数据库锁定异常

时间:2013-07-11 11:52:02

标签: c# .net sqlite ado.net system.data.sqlite

我仅从 SQLite 获取数据库已锁定例外,仅用于某些查询。

以下是我的代码: 当我执行任何select语句时,它工作正常 当我在Jobs表上执行任何写语句时,它也可以正常工作。

这很好用:

ExecuteNonQuery("DELETE FROM Jobs WHERE id=1");

但是,如果我正在执行Employees表的查询,它会抛出数据库被锁定的异常。
抛出异常:

ExecuteNonQuery("DELETE FROM Employees WHERE id=1");

以下是我的功能:

public bool OpenConnection()
{
    if (Con == null)
    {
        Con = new SQLiteConnection(ConnectionString);
    }
    if (Con.State == ConnectionState.Closed)
    {
        Con.Open();
        //Cmd = new SQLiteCommand("PRAGMA FOREIGN_KEYS=ON", Con);
        //Cmd.ExecuteNonQuery();
        //Cmd.Dispose();
        //Cmd=null;
        return true;
    }
    if (IsConnectionBusy())
    {
        Msg.Log(new Exception("Connection busy"));
    }
    return false;
}

public Boolean CloseConnection()
{
    if (Con != null && Con.State == ConnectionState.Open)
    {
        if (Cmd != null) Cmd.Dispose();
        Cmd = null;
        Con.Close();
        return true;
    }

    return false;
}

public Boolean ExecuteNonQuery(string sql)
{
    if (sql == null) return false;
    try
    {
        if (!OpenConnection())
            return false;
        else
        {
            //Tx = Con.BeginTransaction(IsolationLevel.ReadCommitted);
            Cmd = new SQLiteCommand(sql, Con);
            Cmd.ExecuteNonQuery();
            //Tx.Commit();
            return true;
        }
    }
    catch (Exception exception)
    {
        //Tx.Rollback();
        Msg.Log(exception);
        return false;
    }
    finally
    {
        CloseConnection();
    }
}

这是例外: 在第103行:Cmd.ExecuteNonQuery();

  

发现异常:         键入:System.Data.SQLite.SQLiteException        消息:数据库已锁定       数据库被锁定        来源:System.Data.SQLite

     

Stacktrace:在System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt)          在System.Data.SQLite.SQLiteDataReader.NextResult()          在System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd,CommandBehavior表现)          在System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior行为)          在System.Data.SQLite.SQLiteCommand.ExecuteNonQuery()          在D:\ Projects \ C#Applications \ Completed Projects \ TimeSheet6 \ TimeSheet6 \ DbOp.cs中的TimeSheet6.DbOp.ExecuteNonQuery(String sql):第103行

6 个答案:

答案 0 :(得分:82)

沿途某处连接处于打开状态。摆脱OpenConnectionCloseConnection并将ExecuteNonQuery更改为:

using (SQLiteConnection c = new SQLiteConnection(ConnectionString))
{
    c.Open();
    using (SQLiteCommand cmd = new SQLiteCommand(sql, c))
    {
        cmd.ExecuteNonQuery();
    }
}

此外,将读取数据的方式更改为:

using (SQLiteConnection c = new SQLiteConnection(ConnectionString))
{
    c.Open();
    using (SQLiteCommand cmd = new SQLiteCommand(sql, c))
    {
        using (SQLiteDataReader rdr = cmd.ExecuteReader())
        {
            ...
        }
    }
}

请勿尝试,自行管理连接池,就像您在这里一样。首先,它比你编码的要复杂得多,但其次,它已经在SQLiteConnection对象内处理了。最后,如果你没有利用using,那么你没有正确处理这些对象,你最终会遇到像你现在看到的问题。

答案 1 :(得分:14)

您可以使用下面的“使用”声明,这将确保连接&即使在异常

中,命令也能正确处理
private static void ExecuteNonQuery(string queryString)
{
    using (var connection = new SQLiteConnection(
               ConnectionString))
    {
        using (var command = new SQLiteCommand(queryString, connection))
        {
            command.Connection.Open();
            command.ExecuteNonQuery();
        }
    }
}

答案 2 :(得分:2)

在尝试将任何数据写入数据库之前,应关闭DataReader。使用:

dr.Close();

使用完DataReader后。

答案 3 :(得分:0)

我在这里也遇到了同样的错误:

if (new basics.HindiMessageBox(HMsg, HTitle).ShowDialog()==true)
{
    SQLiteConnection m_dbConnection = new SQLiteConnection(MainWindow.con);
    m_dbConnection.Open();
    sql = "DELETE FROM `users`  WHERE `id`=" + SelectedUser.Id;
    command = new SQLiteCommand(sql, m_dbConnection);
    command.ExecuteNonQuery();
    m_dbConnection.Close();
    LoadUserDG();
}

但是当我刚刚更改了SQLiteConnection declearation的地方时

public partial class User : Window
{
    SQLiteCommand command;
    string sql;
    AddUser AddUserObj;
    List<basics.users> usersList;
    basics.users SelectedUser;
    SQLiteConnection m_dbConnection;

    // ...

    private void DeleteBtn_Click(object sender, RoutedEventArgs e)
    {
        // ...
        if (new basics.HindiMessageBox(HMsg, HTitle).ShowDialog()==true)
        {
            m_dbConnection = new SQLiteConnection(MainWindow.con);
            m_dbConnection.Open();
            sql = "DELETE FROM `users`  WHERE `id`=" + SelectedUser.Id;
            command = new SQLiteCommand(sql, m_dbConnection);
            command.ExecuteNonQuery();
            m_dbConnection.Close();
            LoadUserDG();
        }
}
现在一切都很好。 希望它也适合你。 如果有人能说出这是怎么发生的,请告诉我想要提高我的知识。

答案 4 :(得分:0)

在我看来,这很愚蠢,我在SQLite浏览器中进行了更改,没有单击写入更改,从而将数据库锁定为可以通过服务进行修改。单击“写入更改”按钮后,所有发布请求均按预期方式工作。

答案 5 :(得分:0)

这里有很多对那些可能忘记清理悬空连接的人有用的帖子,但是还有另一种可能的发生方式:SQLite不支持并发INSERT;如果您同时发出两个INSERT,则将以串行方式处理。当INSERT快速时,这很好,但是如果INSERT花费的时间超过超时时间,则第二个INSERT可能会失败,并显示此消息。

当我使用长时间运行的事务将一堆INSERT累积到一个大提交中时,便发生了这种情况。基本上,我在交易期间将数据库锁定为其他任何活动。切换到journal_mode=WAL将允许并发写入和读取,但不允许并发写入。

我摆脱了长期运行的事务,让每个INSERT自动提交,这解决了我的问题。