解决SQLite database is locked
前些时候,同事在站点服务端使用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”错误。 测试程序如下:
staticvoidMain(string[]args) {for(inti=0;i<140;i++) { ParameterizedThreadStartpStart=newParameterizedThreadStart(ClientTest.Excute); Threadtd=newThread(pStart); td.Start(1012+i); } Console.Read(); }classClientTest {publicstaticvoidExcute(Objectid) {boolflag=true;while(true) {if(flag) {stringsql="updateasr_infosetasr_check=1whereid='"+id.ToString()+"'"; Sqlite.ExecuteSql(sql); flag=false; }else {stringsql="updateasr_infosetasr_check=0whereid='"+id.ToString()+"'"; Sqlite.ExecuteSql(sql); flag=true; } } } }
测试发现,在i5 2.5Ghz 四核的机器上,跑了不到半分钟,大概执行了500条Update语句,Sqlite就报错,提示“database is locked”,但是在差一点的机器上很难重现,这也就解释了开发机上难重现而在客户服务器上报错的现象。 解决办法:
privatestaticreadonlyobjectobj=newobject();privatestaticintExecuteNonQuery(stringStrSQL,CommandTypeCmdType,SQLiteParameter[]SQLiteParams) { SQLiteConnectionSQLiteConn=newSQLiteConnection(strConn); SQLiteCommandSQLiteCmd=SQLiteCommandConstructor(SQLiteConn,StrSQL,CmdType,SQLiteParams);if(SQLiteConn.State!=ConnectionState.Open) { SQLiteConn.Open(); } Monitor.Enter(obj);intresult=SQLiteCmd.ExecuteNonQuery(); Monitor.Exit(obj);//aaa++;//Console.WriteLine(aaa);SQLiteCmd.Dispose(); SQLiteConn.Close();returnresult; }
事实证明Sqlite不支持并发执行写入操作,即使是不同的表,只支持库级锁,而且这个Sqlite本身没有实现,必须自己实现这个库级锁。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |