为什么我可以在MySql中读取脏行

时间:2010-04-13 19:01:45

标签: mysql concurrency

我无法相信这一点,我总是通过以下内容保证并发安全。

我在一个事务中写入一行,我能够从另一个事务/命令/连接中读取脏值!为什么这不可能(不是我的主要问题)不是这个并不会引起更多麻烦!?!

无论如何,我预计,一旦我写入一行,在交易完成之前,其他任何东西都无法读取该行。并且至少如果仍然可以读取该行将读取干净(原始)值。 (但是如果事务在运行时不使用来自另一个事务的新提交数据,那么这可能会导致问题)

我想数到== 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

1 个答案:

答案 0 :(得分:4)

INNODB表支持交易,MYISAM不支持,确保你是innodb表。