2009-11-18 2 views
1

Для разработки приложения мы должны прочитать строки n строк из таблицы и затем выборочно обновлять эти строки на основе критериев, специфичных для домена. Во время этой операции все остальные пользователи базы данных должны быть заблокированы, чтобы избежать плохих чтений.SQLite Transaction not commit

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

private static SQLiteConnection OpenNewConnection() 
     { 

     try 
     { 
      SQLiteConnection conn = new SQLiteConnection(); 
      conn.ConnectionString = ConnectionString;//System.Configuration.ConfigurationManager.AppSettings["ConnectionString"]; 
      conn.Open(); 
      return conn; 
     }    
     catch (SQLiteException e) 
     { 
      LogEvent("Exception raised when opening connection to [" + ConnectionString + "]. Exception Message " + e.Message); 
      throw e; 
     } 
    } 

    SQLiteConnection conn = OpenNewConnection(); 
      SQLiteCommand command = new SQLiteCommand(conn); 
      SQLiteTransaction transaction = conn.BeginTransaction(); 
// Also fails   transaction = conn.BeginTransaction(); 
      transaction = conn.BeginTransaction(IsolationLevel.ReadCommitted); 
      command.CommandType = CommandType.Text; 
      command.Transaction = transaction; 
      command.Connection = conn; 
      try 
      { 
       string sql = "select * From X Where Y;"; 
       command.CommandText = sql; 
       SQLiteDataReader ranges; 

       ranges = command.ExecuteReader(); 
       sql = string.Empty; 
       ArrayList ret = new ArrayList(); 
       while (MemberVariable > 0 && ranges.Read()) 
       { 
        // Domain stuff 

        sql += "Update X Set Z = 'foo' Where Y;"; 
       } 
       ranges.Close(); 
       command.CommandText = sql; 
       command.ExecuteNonQuery(); 
           // UPDATES NOT BEING APPLIED 
       transaction.Commit(); 
       return ret; 

      } 
      catch (Exception ex) 
      { 
       transaction.Rollback(); 
       throw; 
      } 
      finally 
      { 
       transaction.Dispose(); 
       command.Dispose(); 
       conn.Close(); 
      } 

      return null; 

Если я удалю транзакцию, все будет работать так, как ожидалось. «Доменный материал» является доменным specfic, и кроме чтения значений из набора записей не открывается база данных. Я забыл шаг?

+2

Кто-нибудь заметил, насколько странно, что этот сайт использует полосы прокрутки на странице, несмотря на то, как часто Джефф Этвуд жалуется на этот вид дизайна? – marr75

ответ

4

Когда вы положили точку останова на свою транзакцию. Commit() вы видите, что она попала в цель?

Окончательный ответ:

замок SQLite не работает, как Вы предполагаете увидеть http://www.sqlite.org/lockingv3.html. Учитывая, что, я думаю, что у вас возникли проблемы транзакций рамочных, который может быть легко решен путем реорганизации коды, как например:

string selectSql = "select * From X Where Y;";  
using(var conn = OpenNewConnection()){ 
    StringBuilder updateBuilder = new StringBuilder(); 

    using(var cmd = new SQLiteCommand(selectSql, conn)) 
    using(var ranges = cmd.ExecuteReader()) { 
     while(MemberVariable > 0 && ranges.Read()) { 
      updateBuilder.Append("Update X Set Z = 'foo' Where Y;"); 
     } 
    } 

    using(var trans = conn.BeginTransaction()) 
    using(var updateCmd = new SQLiteCommand(updateBuilder.ToString(), conn, trans) { 
     cmd.ExecuteNonQuery(); 
     trans.Commit(); 
    } 
} 
+0

yes и вызов ExecuteNonQuery возвращает правильное количество модифицированных строк. – MikeP

+0

Давайте сделаем шаг назад: почему вы так рано открываете транзакцию? – JeffreyABecker

+0

Стол, который читается и записывается, является одной и той же таблицей, и все обновления должны быть последовательными между разными пользователями. Приложение должно блокировать дополнительные чтения до тех пор, пока не будет записан текущий запрос. – MikeP

2

Дополнительных замечаний относительно некоторых комментариев в этой записи/ответ о сделках в SQLite. Они применяются к SQLite 3.x, используя журнал и могут или не могут применяться к различным конфигурациям. WAL немного отличается, но я не знаком с ним. Для получения окончательной информации см. locking in SQLite.

Все транзакции в SQLite: SERIALIZABLE (см. Прагму read_uncommitted за одно небольшое исключение). A новый чтение не будет блокировать/сбой , если только не начат процесс записи (есть блокировка EXCLUSIVE/PENDING), и запись не начнется до тех пор, пока все незавершенные чтения не будут завершены, и он может получить блокировку EXCLUSIVE (это неверно для WAL, но изоляция транзакций по-прежнему сохраняется).

Это не будет атомарным номером в коде и последовательность может быть прочитана (A) -> read (B) -> write (A) -> read (B), где A и B представляют разные соединения (представьте себе на разных потоках). На обоих чтениях (B) данные все еще согласованы, хотя между ними была запись.

Чтобы сделать последовательность кода самой атомой, требуется lock или аналогичный механизм синхронизации. Альтернативно, блокировка/синхронизация может быть создана с помощью самого SQLite, используя прагму locking_mode «эксклюзивный». Однако, даже если выше код не является атомарной данных будут прилипать к SQL сериализуемого контракту (за исключением серьезной ошибки ;-)

Happy кодирования


См Locking in SQLite, SQLite pragmas и Atomic Commit in SQLite

Смежные вопросы