2011-03-20 74 views
10

我正在使用System.Data.Sqlite訪問C#中的SQLite數據庫。我有一個查詢必須通過表中的行讀取。在遍歷行時以及閱讀器打開時,必須執行某些SQL更新。我遇到了「數據庫被鎖定」異常。如何在不鎖定數據庫的情況下使用數據讀取器執行SQLite查詢?

SQLite documentation狀態:

當一個進程需要從數據庫中讀取文件,它遵循的步驟順序如下:

  1. 打開數據庫文件,並獲得共享鎖。關於 「共享」 鎖定

的文件進一步指出:

數據庫可以讀,但不能寫。任何數量的進程可以同時保存SHARED鎖,因此可以有多個同時讀取。但是,當一個或多個SHARED鎖處於活動狀態時,不允許其他線程或進程寫入數據庫文件。

FAQ狀態:

多個進程可以同時打開同一個數據庫。多個進程可以同時做一個SELECT。但是,只有一個過程可以隨時對數據庫進行更改。

The Definitive Guide to SQLite狀態:

...的連接可以選擇使用read_uncommited編譯一個讀未提交隔離級別。如果它設置爲true,那麼連接將不會在它讀取的表上放置讀鎖定。因此,另一個寫入程序實際上可以更改表,因爲處於只讀未提交模式下的連接既不能阻止也不能被任何其他連接阻止。

我試圖設置編譯閱讀SQL查詢命令語句內未提交如下:

PRAGMA read_uncommitted = 1; 
SELECT Column1, Column2 FROM MyTable 

使用還是失敗,一個「數據庫不同的連接在同一個線程上的SQL更新被鎖定「例外。然後我試圖將連接實例上的隔離級別設置爲未提交讀取。同樣的例外情況仍然沒有改變。

我該如何完成讓一個開放的數據讀取器循環遍歷數據庫中的行而不鎖定數據庫,以便我可以執行更新?

更新:

以下工作這兩個答案。然而,我已經從使用默認回滾日誌到現在使用Write-Ahead Logging,它提供了改進的數據庫讀取和寫入併發性。

回答

8

使用WAL模式。

+0

我使用ADO.Net。據http://sqlite.phxsoftware.com/ System.Data.SQLite.dll的版本1.0.66.0 2010年4月18日和SQLite的版本爲3.6.23.1。看來我需要3.7+版本才能使用WAL。有什麼建議麼?是否有更新的ADO.Net提供程序? – Elan 2011-03-20 21:33:28

+0

是的,請參閱http://system.data.sqlite.org/index.html/doc/trunk/www/index.wiki 2011年2月版本1.0.68.0是與SQLite代碼合併3.7.5 – 2011-03-21 02:35:24

+0

它看起來很有前途;不幸的是,我沒有看到任何東西準備好或可供下載...是否提供官方提供的1.0.68.0版本,還是這是一個alpha/beta版本? – Elan 2011-03-21 17:39:34

2

我無法使用來自here的開源數據提供程序來使用它。但是,我能夠使用免費標準版dotConnect獲得此工作,如下所示:

創建下面的DLL導入,以便我們可以爲SQLite啓用共享緩存。

[DllImport("sqlite3.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern int sqlite3_enable_shared_cache(int enable); 

執行上述功能啓用共享緩存。請注意,這隻需要在整個過程中執行一次 - 請參閱SQLite documentation

sqlite3_enable_shared_cache(1); 

然後前綴使用的數據讀取器與編譯語句SQL查詢語句如下:

PRAGMA read_uncommitted = 1; 
SELECT Column1, Column2 FROM MyTable 

之一,而在數據讀取器處於活動狀態現在可以自由地更新和插入行。有關共享緩存的其他SQLite文檔可以在here找到。

更新:

的Devart SQLite的數據提供者的較新版本現在支持此以改進的方式。 要啓用共享緩存可以進行下面的調用:

Devart.Data.SQLite.SQLiteConnection.EnableSharedCache(); 

一個可以配置未提交讀入例如連接字符串如下:

Devart.Data.SQLite.SQLiteConnectionStringBuilder builder = new SQLiteConnectionStringBuilder(); 
builder.ReadUncommitted = true; 
builder.DateTimeFormat = Devart.Data.SQLite.SQLiteDateFormats.Ticks; 
builder.DataSource = DatabaseFilePath; 
builder.DefaultCommandTimeout = 300; 
builder.MinPoolSize = 0; 
builder.MaxPoolSize = 100; 
builder.Pooling = true; 
builder.FailIfMissing = false; 
builder.LegacyFileFormat = false; 
builder.JournalMode = JournalMode.Default; 
string connectionString = builder.ToString(); 
相關問題