2009-11-18 5 views
1

우리가 개발중인 응용 프로그램의 경우 표에서 행 n 행을 읽고 도메인 특정 기준에 따라 행을 선택적으로 업데이트해야합니다. 이 작업을 수행하는 동안 데이터베이스의 다른 모든 사용자는 잘못된 읽기를 방지하기 위해 잠글 필요가 있습니다.SQLite 트랜잭션이 적용되지 않습니다.

트랜잭션을 시작하고 행을 읽은 다음 레코드 세트를 반복하는 동안 업데이트 명령문 문자열을 작성합니다. 레코드 세트를 읽은 후에 레코드 세트를 닫고 업데이트를 실행합니다. 이 시점에서 나는 트랜잭션을 커미트하지만 업데이트는 데이터베이스에서 수행되지 않습니다.

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; 

트랜잭션을 제거하면 모든 것이 예상대로 작동합니다. "Domain stuff"은 도메인 지정이며 레코드 세트의 값을 읽는 것 이외의 다른 값은 데이터베이스에 액세스하지 않습니다. 나는 한 걸음 잊었 니?

+2

제프 앳 우드 (Jeff Atwood)가 이런 종류의 디자인에 대해 불만을 품고 있음에도 불구하고이 사이트에서 스크롤 막대를 사용한다는 것이 얼마나 이상한 일인지 알아 챘습니까? – marr75

답변

4

트랜잭션에 중단 점을 넣을 때 커밋() 행에 충돌이 발생합니까?

최종 답변 : 당신이 http://www.sqlite.org/lockingv3.html을 볼 가정하는 것처럼

SQLite는의 잠금이 작동하지 않습니다. 주어진, 난 당신이 쉽게 같은 코드를 재구성하여 해결할 수 있습니다 트랜잭션 범위 지정 문제를 가지고 있다고 생각 : SQLite는의 거래에 대해이 게시물/답변에서 일부 의견에 대한

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

예와 ExecuteNonQuery 호출은 수정 된 행의 정확한 수를 반환합니다. – MikeP

+0

한 걸음 뒤로 물러나십시오. 왜 일찍 거래를 여는거야? – JeffreyABecker

+0

읽고 쓰는 테이블은 동일한 테이블이며 테이블에 대한 모든 업데이트는 서로 다른 사용자간에 순차적이어야합니다. 앱은 현재 요청이 기록 될 때까지 추가 읽기를 차단해야합니다. – MikeP

2

추가 메모를. 이것들은 저널링을 사용하는 SQLite 3.x에 적용되며 다른 구성에 적용될 수도 있고 적용되지 않을 수도 있습니다 - WAL은 약간 다르지만 익숙하지 않습니다. 정확한 정보는 locking in SQLite을 참조하십시오.

SQLite의 모든 트랜잭션은 SERIALIZABLE입니다 (한 가지 예외가 있지만 read_uncommittedpragma 참조). A 쓰기 프로세스가 시작되지 않은 경우 (EXCLUSIVE/PENDING 잠금 보유) 읽기가 완료되지 않고 모든 읽기가 완료 될 때까지 쓰기가 시작되지 않고 EXCLUSIVE 잠금을 얻을 수없는 경우 읽기는 을 차단/실패하지 않습니다 이것은 WAL에 대해서는 사실이 아니지만 트랜잭션 격리는 여전히 동일합니다.

위의 전체 시퀀스는 코드의 원자가되지 않으며 시퀀스는 (A) -> 읽기 (B) -> 쓰기 (A) -> 읽기 (B) 일 수 있습니다. B는 서로 다른 연결을 나타냅니다 (다른 스레드 상상). 두 가지 읽기 (B)에서 데이터는 중간에 쓰기가 있더라도 일관성이 유지됩니다.

코드 자체의 시퀀스를 원자 번호 lock 또는 이와 유사한 동기화 메커니즘으로 만들려면 다음이 필요합니다. 또는 locking_modepragma를 "exclusive"로 사용하여 SQLite 자체로 잠금/동기화를 만들 수 있습니다. 그러나, 위의 코드 원자 수없는 경우에도 데이터


Locking in SQLite, SQLite pragmasAtomic Commit in SQLite

를 참조 심각한 버그 ;-)

해피 코딩을 제외한 SQL 직렬화 계약 (준수합니다

관련 문제