我如何停止数据库文件被锁定异常?

时间:2009-11-25 21:43:35

标签: c# .net sqlite ado.net

我有一个使用sqlite的多线程应用程序。当两个线程尝试立即更新数据库时,我得到异常

Additional information: The database file is locked

它会在几毫秒内重试。我的疑惑并不复杂。最复杂的(经常发生)是更新,选择,运行琐碎的代码更新/删除,提交。为什么抛出异常?如何在抛出异常之前重试几次?

3 个答案:

答案 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之外的其他内容。