【发布时间】:2009-08-03 20:01:11
【问题描述】:
我正在对 SQLite 数据库执行大量 INSERTS。我只使用一个线程。我批量写入以提高性能并在发生崩溃时有一点安全性。基本上我在内存中缓存了一堆数据,然后当我认为合适时,我循环所有这些数据并执行插入。代码如下所示:
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。
- db 是本地文件。
- 所有这些活动都封装在一个线程/进程中。
- 病毒防护已关闭(尽管我认为这仅在您通过网络连接时才相关?)。
- 根据 Scotsman 的帖子,我实施了以下更改:
- 日志模式设置为持久
- 通过
System.Windows.Forms.Application.AppDatawindows 调用存储在 C:\Docs + Settings\ApplicationData 中的 DB 文件 - 没有内部异常
- 在两台不同的机器上见证(尽管硬件和软件非常相似)
- 一直在运行 Process Monitor - 没有无关的进程将自己附加到 DB 文件 - 问题肯定出在我的代码中...
有人知道这里发生了什么吗?
我知道我刚刚丢掉了一堆乱七八糟的代码,但我试图解决这个问题已经太久了。感谢任何完成此问题的人!
布莱恩
更新:
感谢到目前为止的建议!我已经实施了许多建议的更改。我觉得我们离答案越来越近了……但是……
上面的代码在技术上是有效的,但是它是不确定的!除了永远处于空档旋转之外,不能保证做任何事情。在实践中,它似乎在第 1 次和第 10 次迭代之间起作用。如果我以合理的间隔批量提交我的提交,损害将得到减轻,但我真的不想让事情处于这种状态......
欢迎提出更多建议!
【问题讨论】:
-
虽然您不希望有较小的提交 - 当您将 begin tran 和 commit tran 移动到内部批处理循环时问题仍然存在吗?