最近一個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版:
下載
轉載請注明出處:原文http://www.cnblogs.com/yangzhj/p/4230123.html
(全文完)
-------------------------------------------
2015-01-17 10:45 PS:
發現之前提供的下載庫x86版本編譯有些問題。現已重新編譯,且SQLite.Interop.dll均編譯為靜態鏈接,方便遷移使用。謝謝。
