我有一个使用sqlite的多线程应用程序。当两个线程尝试立即更新数据库时,我得到异常
Additional information: The database file is locked
我想它会在几毫秒内重试。我的疑惑并不复杂。最复杂的(经常发生)是更新,选择,运行琐碎的代码更新/删除,提交。为什么抛出异常?如何在抛出异常之前重试几次?
答案 0 :(得分:3)
SQLite对于访问不是线程安全的,这就是您收到此错误消息的原因。
每当您进行更新时,您应该同步对数据库的访问权限(创建对象并“锁定”它)。这将导致第二个线程阻塞并等待第一个线程的更新自动完成。
答案 1 :(得分:1)
尝试尽可能缩短您的事务/提交块。唯一一次你可以死锁/阻止是一个交易 - 因此如果你不这样做,你将没有问题。
也就是说,有时您需要进行交易(主要是数据更新),但如果您可以避免它,则不要在“运行简单代码”时执行这些操作。
答案 2 :(得分:0)
更好的方法可能是使用更新队列,如果您可以使用其余代码进行数据库更新。例如,您可以执行以下操作:
m_updateQueue.Add(()=>InsertOrder(o));
然后你可以有一个处理队列的专用更新线程。
该代码看起来与此类似(我没有编译或测试过它):
class UpdateQueue : IDisposable
{
private object m_lockObj;
private Queue<Action> m_queue;
private volatile bool m_shutdown;
private Thread m_thread;
public UpdateQueue()
{
m_lockObj = new Object();
m_queue = new Queue<Action>();
m_thread = new Thread(ThreadLoop);
m_thread.Start();
}
public void Add(Action a)
{
lock(m_lockObj)
{
m_queue.Enqueue(a);
Monitor.Pulse(m_lockObj);
}
}
public void Dispose()
{
if (m_thread != null)
{
m_shutdown = true;
Monitor.PulseAll(m_lockObj);
m_thread.Join();
m_thread = null;
}
}
private void ThreadLoop()
{
while (! m_shutdown)
{
Action a;
lock (m_lockObj)
{
if (m_queue.Count == 0)
{
Monitor.Wait(m_lockObj);
}
if (m_shutdown)
{
return;
}
a = m_queuue.Dequeue();
}
a();
}
}
}
或者,您可以使用Sql Lite之外的其他内容。