最近一个C#小程序,希望将SQLite数据库放在网络共享的位置,让多个客户端同时访问。却发现SQLite连接不上该网络位置的数据库,而如果数据库在本地则一切正常。
例如将SQLite数据库 test.dat 放在共享位置:\\System\Data\test.dat,
通过SQLite创建数据库连接,执行Open时,将抛掷异常:
SQLite error (14): os_win.c:36702: (3) winOpen(D:\System\Data\test.dat) - 系统找不到指定的路径。
SQLite error (14): os_win.c:36702: (3) winOpen(D:\System\Data\test.dat) - 系统找不到指定的路径。
SQLite error (14): cannot open file at line 36711 of [9491ba7d73]
“System.Data.SQLite.SQLiteException”类型的第一次机会异常在 System.Data.SQLite.dll 中发生
System.Data.SQLite.SQLiteException (0x80004005): unable to open database file
在 System.Data.SQLite.SQLite3.Open(String strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, Int32 maxPoolSize, Boolean usePool)
在 System.Data.SQLite.SQLiteConnection.Open()
在 MyMemory.Frame.DAL.SQLiteRunner..ctor(String connectionString) 位置 d:\Work\Program\WPF\MyMemory\MyMemory.Frame\DAL\SQLiteRunner.cs:行号 34
在 MyMemory.Frame.DAL.DatabaseServices.CreateConnection() 位置 d:\Work\Program\WPF\MyMemory\MyMemory.Frame\DAL\DatabaseServices.cs:行号 23
在 MyMemory.Frame.DAL.DatabaseServices.Initialize(String dataDir) 位置 d:\Work\Program\WPF\MyMemory\MyMemory.Frame\DAL\DatabaseServices.cs:行号 54
“System.Data.SQLite.SQLiteException”类型的第一次机会异常在 MyMemory.Frame.dll 中发生
System.Data.SQLite.SQLiteException (0x80004005): unable to open database file
在 System.Data.SQLite.SQLite3.Open(String strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, Int32 maxPoolSize, Boolean usePool)
在 System.Data.SQLite.SQLiteConnection.Open()
...
即传入的SQLite网络共享路径(以\\开头)在SQLite内部某个环节被转换成为了本地路径!
问题处在SQLite提供的程序集内,那么SQLite最新版本是否已经修复这个问题了(或是从某版故意为之,不让访问网络共享位置的文件了呢)?
到官网http://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki下载最新版本( System.Data.SQLite 1.0.94.0 (3.8.6) )替换后重试,还是出现上面的异常。
好吧,既然是开源的,那就下载源代码,看看是什么原因。
下载了之后,采用VS编译,通过解决方案中自带的Test项目,可以输入数据库链接:
点击Run就可以进入断点调试了。
废话少说,直接上结果:
Open过程问题点的方法调用过程如下
\sqlite-netFx-source-1.0.94.1\System.Data.SQLite\SQLiteConnection.cs Line 2372
SortedList<string, string> opts = ParseConnectionString(
_connectionString, _parseViaFramework);\sqlite-netFx-source-1.0.94.1\System.Data.SQLite\SQLiteConnection.cs Line 1875
arParts = SQLiteConvert.NewSplit(s, ‘;‘, true, ref error);\sqlite-netFx-source-1.0.94.1\System.Data.SQLite\SQLiteConvert.cs Line 716
if ((character != EscapeChar) &&
(character != QuoteChar) &&
(character != separator))将上面的if ( //(character != EscapeChar) && 注释掉后半行(注意:不推荐这种注释代码的方法)
(character != QuoteChar) &&
(character != separator))
再编译,重新执行Test.exe 一切OK。
至于为什么有这个限制,源代码中的注释是:
// --Line 709
// HACK: Only consider the escape character to be an actual
// "escape" if it is followed by a reserved character;
// otherwise, emit the original escape character and
// the current character in an effort to help preserve
// the original string content.
// --Line 715
官方文档说,放在网络位置共享访问的SQLite数据库,在某些特定情况下容易损坏。看来这个问题大神们解决不好,准备干脆屏蔽掉这种使用方式了。
提醒一下,SQLite源码默认用的.Net Framework 4.5,编译时注意切换为项目需要的.Net Framework版本。
最后提供修改后的System.Data.SQLite.dll .Net Framework 4.0版:
下载
转载请注明出处。
(全文完)