2011-07-19 103 views
14

所以我有一個有趣的問題與System.Data.SQLite和使用多個事務。基本上,我有以下的代碼失敗:System.Data.SQLite不支持多個事務

using (IDbConnection connection1 = new SQLiteConnection("connectionstring"), connection2 = new SQLiteConnection("connectionstring")) 
{ 
    connection1.Open(); 
    connection2.Open(); 

    IDbTransaction transaction1 = connection1.BeginTransaction(); 
    IDbTransaction transaction2 = connection2.BeginTransaction(); // Fails! 

    using(IDbCommand command = new SQLiteCommand()) 
    { 
     command.Text = "CREATE TABLE artist(artistid int, artistname text);"; 
     command.CommandType = CommandType.Text; 
     command.Connection = connection1; 
     command.ExecuteNonQuery(); 
    } 

    using (IDbCommand command = new SQLiteCommand()) 
    { 
     command.Text = "CREATE TABLE track(trackid int, trackname text);"; 
     command.CommandType = CommandType.Text; 
     command.Connection = connection2;      
     command.ExecuteNonQuery(); 
    } 

    transaction1.Commit(); 
    transaction2.Commit(); 

} 

從我讀過似乎System.Data.SQLite應該支持嵌套和擴展連續交易。該代碼與下面的異常7號線(其中第二交易申報)失敗:

System.Data.SQLite.SQLiteException: The database file is locked 

System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt) 
System.Data.SQLite.SQLiteDataReader.NextResult() 
System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave) 
System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior) 
System.Data.SQLite.SQLiteCommand.ExecuteNonQuery() 
System.Data.SQLite.SQLiteTransaction..ctor(SQLiteConnection connection, Boolean deferredLock) 
System.Data.SQLite.SQLiteConnection.BeginDbTransaction(IsolationLevel isolationLevel) 
System.Data.Common.DbConnection.System.Data.IDbConnection.BeginTransaction() 

有誰知道問題是什麼或如何解決這個問題?我覺得併發事務對於任何數據庫系統都是必不可少的,所以必須有一些方法來做到這一點。

謝謝!

+1

看起來非常非常緊密你的代碼...在第一次使用聲明你新'command1',但你參考'命令' – JonH

+0

Typo,讓我修復 –

回答

14

OP正在2個連接上啓動事務,這就是問題開始的地方,而不是多個事務本身。

SQLiteConnection conn = new SQLiteConnection("data source=:memory:"); 
conn.Open(); 

var command = conn.CreateCommand(); 
command.CommandText = "create table a (b integer primary key autoincrement, c text)"; 
command.ExecuteNonQuery(); 

var tran1 = conn.BeginTransaction(); 
var tran2 = conn.BeginTransaction(); 

var command1 = conn.CreateCommand(); 
var command2 = conn.CreateCommand(); 

command1.Transaction = tran1; 
command2.Transaction = tran2; 

command1.CommandText = "insert into a VALUES (NULL, 'bla1')"; 
command2.CommandText = "insert into a VALUES (NULL, 'bla2')"; 

command1.ExecuteNonQuery(); 
command2.ExecuteNonQuery(); 

tran1.Commit(); 
tran2.Commit(); 

command.CommandText = "select count(*) from a"; 
Console.WriteLine(command.ExecuteScalar()); 
-1

對於它的價值,不支持每個單連接的多個事務似乎是數據提供者(我確實知道ODP.NET,可能是其他人)的常見情況。

解決此問題的一種方法是爲每個單獨的IDbTransaction單獨提供IDbConnection

- 編輯---

Doh!我只是意識到你有多個連接。抱歉。

+0

sqlite支持多個事務。 – 2011-07-19 15:21:26

-1

SQLite不支持多個事務 - 它在事務中鎖定整個數據庫(請參閱www.sqlite.org)。

編輯: 支持多個事務,但在多個事務中使用DDL時不支持。

+0

這是不正確的。 – 2011-07-19 15:21:07

+0

當比較Oracle中的多個事務支持(例如SQLite)時,您會看到SQLite只是「模擬」對它的支持......您的示例和原始問題之間存在差異,您使用DML,並且他使用DDL這兩個交易...我相應地調整了我的答案。 – Yahia

3

SQLite被設計爲輕量級數據庫,用於諸如瀏覽器中的書籤或照片目錄程序中的照片。 SQLite有一個非常精細的鎖定系統,它針對具有多個閱讀器或單個讀寫器線程的場景進行了優化。因此,它被稱爲具有併發寫入的性能問題 - 它沒有被設計用於具有許多共同作者的應用程序。你可以併發寫入,但它不會很好地擴展。

在這種情況下,這個問題是因爲你正試圖使併發模式改變 - 如果你不是做多SELECT或多個INSERT語句那麼這個工作成功(如sixfeetsix的答案所示)。

如果您的應用程序有很多讀者並沒有太多的作家則SQLite的可能是正常,但是如果你有許多併發讀者和作家一個應用程序,那麼你可能會發現一個完全成熟的數據庫服務器更適合。

有關更多詳細信息,請參閱File Locking And Concurrency In SQLite Version 3

+0

gee第三個答案就是這樣... sqlite _does_支持多個事務。 – 2011-07-19 15:21:45

+0

@sixfeetsix我最近的編輯是否更清楚一點? – Justin

+1

是的,我現在正在考慮一點,因爲我現在明白了你的觀點,但我的觀點是,如果我把自己放在OP的鞋子裏,我發現我更喜歡社區更直接地解決我的問題,即堅持告訴我,多個寫連接是問題,然後作爲一個額外的討論,爲什麼堅持只有一個事務可能會更好。 – 2011-07-19 15:37:58

1

嘗試使用:

((SQLiteConnection)connection).BeginTransaction(true)- 

的布爾參數講述了deferredLock。但是,請記住,只有在提交第一個事務後才應調用ExecuteNonScalar。