SQLite с TransactionScope и генератором идентификаторов приращения - PullRequest
1 голос
/ 22 марта 2010

При попытке использовать SQLite с System.Transactions TransactionScope с генератором удостоверений в качестве приращения я заметил, что получаю исключение (приведенное ниже вместе с кодом), когда NHibernate пытается получить следующий номер удостоверения.

Похоже, это связано с тем, что новое соединение SQLite выполняет автоматическую регистрацию текущей транзакции.Из того, что я слышал, SQLite поддерживает только одну транзакцию записи, но должен поддерживать несколько операций чтения, поэтому я удивлен тем, что получаю исключение блокировки базы данных для операции чтения.Кто-нибудь использовал SQLite с Transaction Scope таким образом.

Тот же код работает нормально, если я использую транзакцию NHibernate вместо TransactionScope

Блок кода:

           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

1 Ответ

3 голосов
/ 22 марта 2010

Здесь действуют две вещи.

Как вы упомянули, System.Data.SQLite автоматически включится в распределенные транзакции.Это включено по умолчанию и может отключить его, добавив Enlist=no.

Во-вторых, System.Data.SQLite по умолчанию создает транзакции с автоматической блокировкой записи.Это делается исходя из предположения, что если транзакция запущена, запись будет выполнена.Это можно изменить, начав транзакции с Serializable.ReadCommitted.

Значение по умолчанию также можно указать в строке подключения с помощью клавиши DefaultIsolationLevel.Допустимые значения: ReadCommitted и Serializable.Другие уровни изоляции не поддерживаются SQLite.ReadCommitted откладывает блокировку записи, тогда как Serializable немедленно получает блокировку записи.

Если не указано, будет использоваться уровень изоляции по умолчанию, указанный в строке подключения.Если в строке подключения не указан уровень изоляции, используется Serializable.Сериализуемые транзакции используются по умолчанию.В этом режиме механизм получает немедленную блокировку базы данных, и никакие другие потоки не могут начать транзакцию.Другие потоки могут читать из базы данных, но не записывать.

При уровне изоляции ReadCommitted блокировки откладываются и повышаются по мере необходимости.Несколько потоков могут запустить транзакцию в режиме ReadCommitted, но если поток пытается зафиксировать транзакцию, когда другой поток имеет блокировку ReadCommitted, это может привести к таймауту или вызвать взаимоблокировку обоих потоков до достижения CommandTimeout обоих потоков.

...