Я выполняю большое количество INSERTS для базы данных SQLite. Я использую только одну ветку. Я делаю записи для улучшения производительности и обеспечения безопасности в случае сбоя. По сути, я кеширую кучу данных в памяти, а затем, когда считаю нужным, зацикливаю все эти данные и выполняю ВСТАВКИ. Код для этого показан ниже:
public void Commit()
{
using (SQLiteConnection conn = new SQLiteConnection(this.connString))
{
conn.Open();
using (SQLiteTransaction trans = conn.BeginTransaction())
{
using (SQLiteCommand command = conn.CreateCommand())
{
command.CommandText = "INSERT OR IGNORE INTO [MY_TABLE] (col1, col2) VALUES (?,?)";
command.Parameters.Add(this.col1Param);
command.Parameters.Add(this.col2Param);
foreach (Data o in this.dataTemp)
{
this.col1Param.Value = o.Col1Prop;
this. col2Param.Value = o.Col2Prop;
command.ExecuteNonQuery();
}
}
this.TryHandleCommit(trans);
}
conn.Close();
}
}
Теперь я использую следующий трюк, чтобы заставить вещь со временем работать:
private void TryHandleCommit(SQLiteTransaction trans)
{
try
{
trans.Commit();
}
catch (Exception e)
{
Console.WriteLine("Trying again...");
this.TryHandleCommit(trans);
}
}
Я создаю свою БД следующим образом:
public DataBase(String path)
{
//build connection string
SQLiteConnectionStringBuilder connString = new SQLiteConnectionStringBuilder();
connString.DataSource = path;
connString.Version = 3;
connString.DefaultTimeout = 5;
connString.JournalMode = SQLiteJournalModeEnum.Persist;
connString.UseUTF16Encoding = true;
using (connection = new SQLiteConnection(connString.ToString()))
{
//check for existence of db
FileInfo f = new FileInfo(path);
if (!f.Exists) //build new blank db
{
SQLiteConnection.CreateFile(path);
connection.Open();
using (SQLiteTransaction trans = connection.BeginTransaction())
{
using (SQLiteCommand command = connection.CreateCommand())
{
command.CommandText = DataBase.CREATE_MATCHES;
command.ExecuteNonQuery();
command.CommandText = DataBase.CREATE_STRING_DATA;
command.ExecuteNonQuery();
//TODO add logging
}
trans.Commit();
}
connection.Close();
}
}
}
Затем я экспортирую строку подключения и использую ее для получения новых подключений в разных частях программы.
Через, казалось бы, случайные интервалы, хотя со слишком большой скоростью, чтобы игнорировать или иным образом обойти эту проблему, я получаю необработанное исключение SQLiteException: файл базы данных заблокирован. Это происходит, когда я пытаюсь совершить транзакцию. Кажется, до этого не было ошибок. Это не всегда происходит. Иногда все это работает без помех.
- До завершения фиксации не выполняется чтение этих файлов.
- У меня самая последняя версия двоичного файла SQLite.
- Я компилирую для .NET 2.0.
- Я использую VS 2008.
- БД является локальным файлом.
- Все это действие инкапсулировано в одном потоке / процессе.
- Защита от вирусов отключена (хотя я думаю, что это было актуально, только если вы подключались по сети?).
- Согласно сообщению шотландца, я внес следующие изменения:
- Режим журнала установлен на Persist
- Файлы БД, хранящиеся в C: \ Docs + Settings \ ApplicationData через
System.Windows.Forms.Application.AppData
вызов Windows
- Нет внутреннего исключения
- Виден на двух разных машинах (хотя и очень похожих аппаратных и программных)
- Был запущен Process Monitor - никакие посторонние процессы не присоединяются к файлам БД - проблема определенно в моем коде ...
Кто-нибудь знает, что здесь происходит?
Я знаю, что я просто отбросил весь беспорядок кода, но я пытался понять это слишком долго. Спасибо всем, кто дошел до конца этого вопроса!
1055 * Брайен *
ОБНОВЛЕНИЕ:
Спасибо за предложения! Я реализовал многие из предложенных изменений. Я чувствую, что мы приближаемся к ответу ... однако ...
Технически приведенный выше код работает, однако он не является детерминированным! Это не гарантировано, что делать что-либо кроме вращения в нейтральном навсегда. На практике это работает где-то между 1-й и 10-й итерациями. Если я сделаю серию своих коммитов с разумным интервалом, ущерб будет уменьшен, но я действительно не хочу оставлять вещи в этом состоянии ...
Дополнительные предложения приветствуются!