Исключение блокировки базы данных SQLite

Я получаю исключение База данных заблокирована от SQLite только для некоторых запросов.

Ниже мой код: Когда я выполняю любой оператор select, он работает нормально.
Когда я выполняю любой оператор записи в Jobs Table, он также работает нормально.

Это отлично работает:

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, поведение CommandBehavior) в System.Data .SQLite.SQLiteCommand.ExecuteReader (поведение CommandBehavior) в System.Data.SQLite.SQLiteCommand.ExecuteNonQuery () в TimeSheet6.DbOp.ExecuteNonQuery (String sql) в d: \ Projects \ C # Applications \ Completed Projects \ TimeSheet \ Completed Projects \ TimeSheet \ Completed Projects \ TimeSheet \ cs: строка 103


person Community    schedule 11.07.2013    source источник
comment
Убедитесь, что вы закрываете соединение, выполняете ваш запрос.   -  person Vishal Suthar    schedule 11.07.2013
comment
Да, я закрыл все соединения и также удалил командные объекты.   -  person    schedule 11.07.2013
comment
Я сделал много отладки за этим. Кажется, это не проблема открытого соединения.   -  person    schedule 11.07.2013
comment
Он позволяет открывать только одно соединение за раз, поэтому лучше использовать оператор using.   -  person Vishal Suthar    schedule 11.07.2013


Ответы (6)


Где-то по пути связь остается открытой. Избавьтесь от OpenConnection и CloseConnection и замените 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, вы не удаляете эти объекты должным образом, и в конечном итоге возникают проблемы, подобные тому, что вы видите сейчас.

person Mike Perrenoud    schedule 11.07.2013
comment
@coding, да. Всегда есть другие способы заблокировать файлы, но неправильная обработка объектов подключения (например, ваш исходный код) является главным подозреваемым. - person Mike Perrenoud; 11.07.2013
comment
В моем случае проблемой было не закрытие / удаление SQLiteDataReader, несмотря на использование операторов using для соединения и команды. Спасибо, что положили конец разочарованию! - person Luke Zaparaniuk; 05.06.2015
comment
Это спасло мне целых 2 дня, которые позволили мне прижаться к стене. Спасибо - person ysk silver; 13.05.2021

Вы можете использовать оператор using, как показано ниже, чтобы убедиться, что соединение и команда расположены правильно даже в исключении.

private static void ExecuteNonQuery(string queryString)
{
    using (var connection = new SQLiteConnection(
               ConnectionString))
    {
        using (var command = new SQLiteCommand(queryString, connection))
        {
            command.Connection.Open();
            command.ExecuteNonQuery();
        }
    }
}
person Damith    schedule 11.07.2013

Перед попыткой записи каких-либо данных в базу данных следует закрыть DataReader. Использовать:

dr.Close();

после того, как вы закончите использовать DataReader.

person salman    schedule 18.10.2017
comment
Это была моя проблема, у меня много методов, и один из них не закрывает соединение - person Professor Zoom; 09.03.2019

В моем случае это было очень глупо с моей стороны, я вносил изменения в браузере SQLite и не нажимал на запись изменений, что заблокировало изменение БД службами. После того, как я нажал кнопку «Записать изменения», все запросы на публикацию работали, как ожидалось.

person Rohan Shenoy    schedule 13.07.2019

Я также получал ту же ошибку здесь:

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

Теперь все хорошо. Надеюсь, это сработает и для вас. Если кто-то может сказать, как это произошло, я хотел бы узнать подробности, чтобы улучшить свои знания, пожалуйста.

person RAM DANE    schedule 05.07.2017
comment
Вы должны использовать Using везде, где это возможно! Как вам показали Майк Перрено и Дамит. Использование было изобретено для контроля / безопасности, вы действительно должны его использовать. - person tmighty; 25.08.2017

Здесь много полезных сообщений для людей, которые, возможно, забыли очистить оборванное соединение, но есть и другой способ, которым это может произойти: SQLite не поддерживает одновременные операции INSERT; если вы введете два INSERT одновременно, они будут обрабатываться последовательно. Когда INSERT выполняется быстро, это нормально, но если INSERT занимает больше времени, чем тайм-аут, второй INSERT может дать сбой с этим сообщением.

У меня это случилось, когда я использовал длительную транзакцию, чтобы собрать кучу INSERT в одну большую фиксацию. Обычно я блокировал базу данных от любых других действий во время транзакции. Переключение на journal_mode=WAL разрешит одновременную запись и чтение, но не одновременную запись.

Я избавился от длительной транзакции и позволил каждой INSERT автоматически фиксироваться, и это решило мою проблему.

person Andrew    schedule 21.05.2020