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

  Sqlite的特点:

  1. 简单(simple):SQLite是一个非常轻量级自包含(lightweight and self-contained)的DBMS:一个头文件,一个动态库文件,你就拥有了关系数据库的所有功能了。简单,是SQLite最明显的哲学。它提供的API少而简单。只需要一个DLL文件,你的程序马上就拥有了一个功能强大的数据库引擎,这是一件很美妙的事。
  2. 小巧(small):我用VS 2005在Windows下编译的3.6.11,Release版为368K,用时不到20秒——而编译MySQL时,要花上几分钟。而当我插入10000条int数据时,内存开销660K,磁盘开销92K。
  3. 事务(transaction):事务是现代商业数据处理系统最基本的要求,而Access,不论是在可执行文件大小(看了一下Access2003的可执行文件大小为6.32M,两者不是一个量级),还是事务特性,都是不能和SQLite 相比的。
  4. 并发性(Concurrency):由于SQLite通过OS的文件锁来实现库级锁,粒度很大,但是,它通过一些复杂特殊的处理(具体可以参见分析系列),尽量的提升了读写的并发度。如果你还有担心,你可以看看这篇文章:http://www.dbanotes.net/database/sqlite_cms.html
  5. SQL92:SQLite支持绝大部分的标准SQL语句,你只需要几百K的空间,就可以换来需要上百兆的通用DBMS几乎所有操作了。
  6. 方便(Convenience):如果你的程序要使用SQLite,只需要将拷贝你的程序目录即可。
  7. 开源(Opensource):这是它最强大的地方。开源,意味着你可以品读它的源码,你可以随时修改它,加入你自己的特性,而这一切完全免费的。开源,是一种精神

  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 = ; i < ; i++)
{
ParameterizedThreadStart pStart = new ParameterizedThreadStart(ClientTest.Excute);
Thread td = new Thread(pStart);
td.Start( + 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本身没有实现,必须自己实现这个库级锁。

最新文章

  1. H2数据库攻略
  2. mybatis if判断中的特殊符号
  3. 01-C#入门(调试和错误处理)
  4. POJ 3150 Cellular Automaton --矩阵快速幂及优化
  5. Linux里实用命令之添加行号、文本和语法高亮显示
  6. java.text.MessageFormat格式化字符串时的小技巧
  7. ASP.NET页面之间传递值的几种方式(转载)
  8. Django入门实践(三)
  9. struts2中配置文件的调用顺序
  10. [poj3904]Sky Code_状态压缩_容斥原理
  11. 洛谷P1072Hankson的趣味题题解
  12. 三步法搞定CTF中的SQL注入题型
  13. python note 11 函数名的使用、闭包、迭代器
  14. day14(1)--递归、匿名函数、内置函数
  15. 音频标签化2:youtube-8m项目的训练、评估与测试
  16. 【Android】详解Android Activity
  17. HTTP接口-跨域-callback
  18. (转).net面试题(老赵)
  19. Web Service Client使用Microsoft WSE 2.0
  20. Spring boot Thymeleaf 配置

热门文章

  1. 我的新发现:AVL树旋转的一个特性
  2. Python介绍、安装、使用
  3. 在CentOS 7上安装Node.js的4种方法
  4. C# 获取sql数据库表列名,及列名说明备注信息
  5. 简介AngularJS中使用factory和service的方法
  6. 关注微信 即可连上wifi 的设计思路
  7. WebApi 接口测试工具:WebApiTestClient
  8. 解决Eclipse启动Tomcat时报Error loading WebappClassLoader错误
  9. python核心编程学习记录之序列(字符串元组列表)
  10. windows 8.1无人值守安装