57

我只对某些查询 从SQLite获取数据库被锁定异常。

下面是我的代码:当我执行任何选择语句时,它工作正常。
当我在JobsTable 上执行任何 write 语句时,它也可以正常工作。

这工作正常:

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.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior 行为) 在 System.Data.SQLite.SQLiteDataReader.NextResult() 的 System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt) .SQLite.SQLiteCommand.ExecuteReader(CommandBehavior 行为) 在 System.Data.SQLite.SQLiteCommand.ExecuteNonQuery() 在 TimeSheet6.DbOp.ExecuteNonQuery(String sql) 在 d:\Projects\C# Applications\Completed Projects\TimeSheet6\TimeSheet6\DbOp。 CS:第 103 行

4

7 回答 7

99

在某个地方,连接处于打开状态。摆脱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,你就没有正确地处理这些对象,你最终会遇到像你现在看到的那样的问题。

于 2013-07-11T12:02:08.333 回答
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();
        }
    }
}
于 2013-07-11T12:01:39.557 回答
7

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

dr.Close();

使用完 DataReader 后。

于 2017-10-18T13:55:01.697 回答
6

在我的情况下,我非常愚蠢,我在 SQLite 浏览器中进行更改并且没有单击写入更改,这锁定了要由服务修改的数据库。单击“写入更改”按钮后,所有发布请求都按预期工作。

于 2019-07-13T10:12:29.087 回答
1

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

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

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

于 2020-05-21T23:37:19.597 回答
0

从多个线程将大量数据加载到不同的表时,我遇到了同样的问题。在尝试进行插入时,我被锁定了数据库,因为程序插入太多太快,并且 SQLite 没有时间在另一个事务到来之前完成每个事务。

插入是通过线程完成的,因为我不希望接口被锁定并等待插入完成。

我的解决方案是将 BlockingCollection 与 ThreadPool.QueueUserWorkItem 一起使用。这使我可以在插入时释放界面。所有插入都按 FIFO(先进先出)顺序排队和执行。现在,在从任何线程执行任何 SQL 事务时,数据库永远不会被锁定。

public class DatabaseQueueBus
{
    private BlockingCollection<TransportBean> _dbQueueBus = new BlockingCollection<TransportBean>(new ConcurrentQueue<TransportBean>());
    private CancellationTokenSource __dbQueueBusCancelToken;

    public CancellationTokenSource _dbQueueBusCancelToken { get => __dbQueueBusCancelToken; set => __dbQueueBusCancelToken = value; }

    public DatabaseQueueBus()
    {
        _dbQueueBusCancelToken = new CancellationTokenSource();
        DatabaseQueue();

    }

    public void AddJob(TransportBean dto)
    {
        _dbQueueBus.Add(dto);
    }

    private void DatabaseQueue()
    {

        ThreadPool.QueueUserWorkItem((param) =>
        {
            try
            {
                do
                {
                    string job = "";
                    TransportBean dto = _dbQueueBus.Take(_dbQueueBusCancelToken.Token);
                    try
                    {
                        job = (string)dto.DictionaryTransBean["job"];
                        switch (job)
                        {
                            case "SaveClasse":
                                //Save to table here
                                break;
                            case "SaveRegistrant":
                                //Save Registrant here
                                break;
                          
                        }
                    }
                    catch (Exception ex)
                    {//TODO: Handle this exception or not

                    }

                } while (_dbQueueBusCancelToken.Token.IsCancellationRequested != true);
            }
            catch (OperationCanceledException)
            {

            }
            catch (Exception ex)
            {

            }
        });
    }
}

插入是以这种方式完成的,但没有排队我仍然遇到锁定问题。

using (SQLiteConnection c = new SQLiteConnection(BaseDal.SQLiteCon))
        {
            c.Open();
            using (SQLiteCommand cmd = new SQLiteCommand(sql, c))
            {
                cmd.ExecuteNonQuery();
            }
            c.Close();
        }
于 2022-01-31T18:18:55.147 回答
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 声明位置时

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();
        }
}

现在一切都很好。我希望这也对你有用。如果有人能说出这是怎么发生的,我想知道细节以提高我的知识,拜托。

于 2017-07-05T07:59:44.527 回答