1

IDジェネレーターをインクリメントとしてSystem.TransactionsTransactionScopeでSQLiteを使用しようとすると、NHibernateが次のID番号を取得しようとしたときに、例外(以下にコードとともに示されています)が発生していることに気付きました。

これは、新しいSQLite接続が現在のトランザクションの自動登録を実行しているためと思われます。私が聞いたところによると、SQLiteは単一の書き込みトランザクションのみをサポートしていますが、複数の読み取りをサポートする必要があるため、読み取り操作でデータベースロック例外が発生していることに驚いています。誰かがこの方法でトランザクションスコープでSQLiteを使用しましたか?

TransactionScopeの代わりにNHibernateトランザクションを使用すると、同じコードが正常に機能します

コードブロック:

           using (var scope = new TransactionScope()) 
            { 
                var userRepository = 
container.GetInstance<IUserRepository>(); 
                var user = new User(); 
                userRepository.SaveOrUpdate(user); 
                scope.Complete(); 
            } 

例外:

19:34:19,126 ERROR [   7] IncrementGenerator [(null)]- could not get 
increment value 
System.Data.SQLite.SQLiteException: The database file is locked 
database is locked 
   at System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt) 
   at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery() 
   at System.Data.SQLite.SQLiteTransaction..ctor(SQLiteConnection 
connection, Boolean deferredLock) 
   at System.Data.SQLite.SQLiteConnection.BeginTransaction(Boolean 
deferredLock) 
   at System.Data.SQLite.SQLiteConnection.BeginTransaction() 
   at System.Data.SQLite.SQLiteEnlistment..ctor(SQLiteConnection cnn, 
Transaction scope) 
   at 
System.Data.SQLite.SQLiteConnection.EnlistTransaction(Transaction 
transaction) 
   at System.Data.SQLite.SQLiteConnection.Open() 
   at NHibernate.Connection.DriverConnectionProvider.GetConnection() 
   at NHibernate.Id.IncrementGenerator.GetNext(ISessionImplementor 
session) 
19:34:20,063 ERROR [   7] ADOExceptionReporter [(null)]- The database 
file is locked 
database is locked
4

1 に答える 1

3

ここでは2つのことが関係しています。

あなたが言ったように、System.Data.SQLite分散トランザクションに自動参加します。これはデフォルトでオンになっており、を追加することでオフにできますEnlist=no

2つ目は、System.Data.SQLiteデフォルトで自動書き込みロックを使用してトランザクションを作成することです。これは、トランザクションが開始されると書き込みが行われるという前提に基づいて行われます。これは、でトランザクションを開始することでオーバーライドできますSerializable.ReadCommitted

デフォルトは、キーを使用して接続文字列で指定することもできますDefaultIsolationLevelReadCommitted有効な値はとSerializableのみです。他の分離レベルはSQLiteではサポートされていません。 ReadCommitted書き込みロックを延期し、Serializable書き込みロックをすぐに取得します。

Undefinedは、接続文字列で指定されたデフォルトの分離レベルを使用します。接続文字列に分離レベルが指定されていない場合は、Serializableが使用されます。シリアル化可能なトランザクションがデフォルトです。このモードでは、エンジンはデータベースを即座にロックし、他のスレッドはトランザクションを開始できません。他のスレッドはデータベースから読み取ることができますが、書き込むことはできません。

ReadCommitted分離レベルでは、必要に応じてロックが延期され、昇格されます。複数のスレッドがReadCommittedモードでトランザクションを開始することは可能ですが、別のスレッドがReadCommittedロックを持っているときにスレッドがトランザクションをコミットしようとすると、両方のスレッドのCommandTimeoutに達するまで、タイムアウトするか、両方のスレッドでデッドロックが発生する可能性があります。

于 2010-03-22T17:31:21.927 に答える