나는 이것을 믿을 수 없다. 나는 항상 아래에서 동시성이 안전하다고 믿는다.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
Perfect. 이제 블록 : D. (응용 프로그램 잠금, 좋은 징조). –
나는 첫 번째 트랜잭션에서 5 초 동안, 두 번째에서 10 초 동안 잠을 잤다. 코드는 값 11로 완료됩니다. 동시성은 저에게 안전합니다. 사이트가 허용하면 동의 할 것입니다. –