2010-04-13 2 views
1

나는 이것을 믿을 수 없다. 나는 항상 아래에서 동시성이 안전하다고 믿는다.MySql에서 더러운 행을 읽을 수있는 이유는 무엇입니까

한 트랜잭션에서 행에 쓰고 다른 트랜잭션/명령/연결에서 더티 값을 읽을 수 있습니다! 왜 이것이 가능한가 (내 주요 질문이 아님) 이것이 바람직하지 않으며 더 많은 문제를 야기하지 않는다!

어쨌든, 나는 일단 행에 쓰면 트랜잭션이 끝날 때까지 그 행을 읽을 수 없을 것이라고 예상했다. 적어도 행이 여전히 읽을 수 있으면 깨끗한 (원래) 값이 읽혀질 것입니다. (하지만 트랜잭션이 실행될 때 다른 트랜잭션에서 새로 커미트 된 데이터를 사용하지 않는 경우에도 문제가 발생할 수 있습니다)

나는 == 11로 계산하고 싶습니다. 모든 변형에서 안전하다고 생각했습니다. SQL. 내가 뭘 할 수 있습니까? 1) 더티 값을 읽지 않고 깨끗하게 처리합니다. 2) 트랜잭션이 끝날 때까지 해당 행을 잠그지 않았습니까?

static MySqlConnection MakeConn() 
    { 
     string connStr = "server=192.168.126.128;user=root;database=TestDB;port=3306;password=a;"; 
     MySqlConnection conn = new MySqlConnection(connStr); 
     conn.Open(); 
     return conn; 
    } 
    static Semaphore sem1 = new Semaphore(1, 1); 
    static Semaphore sem2 = new Semaphore(1, 1); 
    static void Main2() 
    { 
     Console.WriteLine("Starting Test"); 

     // 
     sem1.WaitOne(); Console.WriteLine("1W"); 
     sem2.WaitOne(); Console.WriteLine("2W"); 
     Thread oThread = new Thread(new ThreadStart(fn2)); 
     oThread.Start(); 

     var conn = MakeConn(); 
     var cmd = new MySqlCommand(@" 
      CREATE TABLE IF NOT EXISTS Persons 
      (
      P_Id int NOT NULL, 
      name varchar(255), 
      count int, 
      PRIMARY KEY (P_Id) 
      )", conn); 
     cmd.ExecuteNonQuery(); 

     cmd.CommandText = "delete from Persons; insert into Persons(name, count) VALUES('E', '4');"; 
     cmd.ExecuteNonQuery(); 

     cmd.CommandText = "select count from Persons;"; 
     var count = (int)cmd.ExecuteScalar(); 

     Console.WriteLine("Finish inserting. v={0}", count); 
     sem2.Release(); Console.WriteLine("2R"); 
     sem1.WaitOne(); Console.WriteLine("1W"); 


     Console.WriteLine("Starting transaction"); 
     using (var tns = conn.BeginTransaction()) 
     { 
      cmd.CommandText = "update Persons set count=count+1"; 
      cmd.ExecuteNonQuery(); 
      cmd.CommandText = "select count from Persons;"; 
      count = (int)cmd.ExecuteScalar(); 
      Console.WriteLine("count is {0}", count); 

      sem2.Release(); Console.WriteLine("2R"); 
      sem1.WaitOne(); Console.WriteLine("1W"); 

      count += 5; //10 

      cmd.CommandText = "update Persons set count=" + count.ToString(); 
      cmd.ExecuteNonQuery(); 
      cmd.CommandText = "select count from Persons;"; 
      count = (int)cmd.ExecuteScalar(); 
      Console.WriteLine("count is {0}", count); 

      tns.Commit(); 
     } 
     Console.WriteLine("finished transaction 1"); 
     sem2.Release(); Console.WriteLine("2R"); 
     sem1.WaitOne(); Console.WriteLine("1W"); 

     cmd.CommandText = "select count from Persons;"; 
     count = (int)cmd.ExecuteScalar(); 
     Console.WriteLine("count is {0}", count); 

     sem2.Release(); Console.WriteLine("2R"); 
     //sem1.WaitOne(); Console.WriteLine("1W"); 

    } 
    static void fn2() 
    { 
     int count; 
     Console.WriteLine("Starting thread 2"); 
     sem2.WaitOne(); Console.WriteLine("1W"); 
     var conn = MakeConn(); 
     var cmd = new MySqlCommand("", conn); 
     sem1.Release(); Console.WriteLine("1R"); 
     sem2.WaitOne(); Console.WriteLine("2W"); 

     using (var tns = conn.BeginTransaction()) 
     { 
      cmd.CommandText = "update Persons set count=count+1"; 
      cmd.ExecuteNonQuery(); 
      cmd.CommandText = "select count from Persons;"; 
      count = (int)cmd.ExecuteScalar(); 
      Console.WriteLine("count is {0}", count); 

      sem1.Release(); Console.WriteLine("1R"); 
      sem2.WaitOne(); Console.WriteLine("2W"); 

      tns.Commit(); 
     } 
     Console.WriteLine("finished transaction 2"); 
     sem1.Release(); Console.WriteLine("1R"); 
     sem2.WaitOne(); Console.WriteLine("2W"); 

     cmd.CommandText = "select count from Persons;"; 
     count = (int)cmd.ExecuteScalar(); 
     Console.WriteLine("count is {0}", count); //should be 11. 4 + 1x2(one each thread) += 5 from first thread == 11 

     sem1.Release(); Console.WriteLine("1R"); 
    } 

콘솔

Starting Test 
1W 
2W 
Starting thread 2 
Finish inserting. v=4 
2R 
1W 
1R 
1W 
Starting transaction 
count is 5 
2R 
2W 
count is 6 
1R 
1W 
count is 10 
finished transaction 1 
2R 
2W 
finished transaction 2 
1R 
1W 
count is 10 
2R 
2W 
count is 10 
1R 

답변

4

INNODB 테이블의 트랜잭션을 지원, MYISAM, 당신은 InnoDB의 테이블을 creatinng되어 있는지 확인하지 않습니다 없습니다.

+0

Perfect. 이제 블록 : D. (응용 프로그램 잠금, 좋은 징조). –

+0

나는 첫 번째 트랜잭션에서 5 초 동안, 두 번째에서 10 초 동안 잠을 잤다. 코드는 값 11로 완료됩니다. 동시성은 저에게 안전합니다. 사이트가 허용하면 동의 할 것입니다. –

관련 문제