欢迎投稿

今日深度:

解决SQLite database is locked,sqlitelocked

解决SQLite database is locked,sqlitelocked


  前些时候,同事在站点服务端使用SQlite存储一些临时数据,但是在多人并发的时候Sqlite会抛出异常:The database file is locked , database is locked,而且这个是在客户生产环境下提示出来的,开发环境很难重现,同事实在没辙,竟然想发动所有研发同事通过操作软件重现问题,我只能呵呵了。既然是Sqlite的原因,直接写个小程序测试下sqlite不就行了,而且就算重现了,难不成要改Sqlite源码...

  Sqlite的特点:

  SQLite只支持库级锁,库级锁意味着什么?——意味着同时只能允许一个写操作,也就是说,即事务T1在A表插入一条数据,事务T2在B表中插入一条数据,这两个操作不能同时进行,即使你的机器有100个CPU,也无法同时进行,而只能顺序进行。表级都不能并行,更别说元组级了——这就是库级锁。但是,SQLite尽量延迟申请X锁,直到数据块真正写盘时才申请X锁,这是非常巧妙而有效的。

  上面的介绍可以看出Sqlite其实是一个客户端嵌入数据库,在高并发的服务器上是无法适用的,同事百度后,发现连接串中加入 "Journal Mode=WAL;"可以缓解并发压力,可是客户生产环境仍然出现“database is locked”错误。

  测试程序如下:

        static void Main(string[] args)
        {
             for (int i = 0; i < 140; i++)
             {
                 ParameterizedThreadStart pStart = new      ParameterizedThreadStart(ClientTest.Excute);
                 Thread td = new Thread(pStart);
                 td.Start(1012 + i);
             }
             Console.Read();
        }


    class ClientTest
    {

        public static void Excute(Object id)
        {
            bool flag = true;
            while (true)
            {
                if (flag)
                {
                    string sql = "update asr_info set asr_check = 1 where id = '" + id.ToString() + "'";
                    Sqlite.ExecuteSql(sql);
                    flag = false;
                }
                else
                {
                    string sql = "update asr_info set asr_check = 0 where id = '" + id.ToString() + "'";
                    Sqlite.ExecuteSql(sql);
                    flag = true;
                }
            }
        }
    }

  测试发现,在i5 2.5Ghz 四核的机器上,跑了不到半分钟,大概执行了500条Update语句,Sqlite就报错,提示“ database is locked”,但是在差一点的机器上很难重现,这也就解释了开发机上难重现而在客户服务器上报错的现象。

  解决办法:

        private static readonly object obj = new object();
        private static int ExecuteNonQuery(string StrSQL, CommandType CmdType, SQLiteParameter[] SQLiteParams)
        {
            SQLiteConnection SQLiteConn = new SQLiteConnection(strConn);
            SQLiteCommand SQLiteCmd = SQLiteCommandConstructor(SQLiteConn, StrSQL, CmdType, SQLiteParams);
            if (SQLiteConn.State != ConnectionState.Open)
            {
                SQLiteConn.Open();
            }
            Monitor.Enter(obj);
            int result = SQLiteCmd.ExecuteNonQuery();
            Monitor.Exit(obj);
            //aaa++;
            // Console.WriteLine(aaa);
            SQLiteCmd.Dispose();
            SQLiteConn.Close();

            return result;
        }

  事实证明Sqlite不支持并发执行写入操作,即使是不同的表,只支持库级锁,而且这个Sqlite本身没有实现,必须自己实现这个库级锁。

www.htsjk.Com true http://www.htsjk.com/SQLite/10468.html NewsArticle 解决SQLite database is locked,sqlitelocked 前些时候,同事在站点服务端使用SQlite存储一些临时数据,但是在多人并发的时候Sqlite会抛出异常:The database file is locked ,database is locked,而且这个是...
相关文章
    暂无相关文章
评论暂时关闭