事务内的FOR UPDATE不会锁定行

时间:2011-01-25 13:32:22

标签: c# .net mysql locking

我做了这个测试,从两个线程中选择一个我之前创建的行:

CREATE TABLE `customers` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`), 
) ENGINE=InnoDB 

    var t1 = new Thread(new ThreadStart(delegate()
    {
        using (var conn = new MySqlConnection("Server=localhost;Database=test;Uid=root;Pwd=test;"))
        {
            conn.Open();
            using (var trans = conn.BeginTransaction())
            {
                using (var cmd = new MySqlCommand("select id from customers where id = 8534 FOR UPDATE;", conn, trans))
                {
                    using (var reader = cmd.ExecuteReader())
                    {
                        Console.WriteLine("Enter t1: " + reader.Read());
                        Thread.Sleep(2000);
                        Console.WriteLine("Exit t1");
                    }
                }
            }
        };
    }));

    var t2 = new Thread(new ThreadStart(delegate()
    {
        using (var conn = new MySqlConnection("Server=localhost;Database=test;Uid=root;Pwd=test;"))
        {
            conn.Open();
            using (var cmd = new MySqlCommand("select id from customers where id = 8534", conn))
            {
                Console.WriteLine("Enter t2: " + cmd.ExecuteScalar());
                Console.WriteLine("Exit t2");
            }
        }
    }));

    t1.Start();
    Thread.Sleep(400);
    t2.Start();

    t1.Join();
    t2.Join();

我得到的结果是:

Enter t1: True
Enter t2: 8534
Exit t2
Exit t1

线程1中的FOR UPDATE是否应该阻止线程2在释放事务之前读取该行?

1 个答案:

答案 0 :(得分:5)

  

线程1中的FOR UPDATE是否应该阻止线程2在释放事务之前读取该行?

没有

但是它会阻止线程2写入这一行(或者用FOR UPDATE子句读取它。)

在默认事务隔离级别(即REPEATABLE READ)中,SELECT语句不会对它们读取的行放置任何锁定。

要锁定SELECT语句,您应该指示它锁定(使用FOR UPDATELOCK IN SHARE MODE或将读者的事务隔离级别设置为SERIALIZABLE。)

来自docs

  

一致性读取是InnoDB处理SELECTREAD COMMITTED隔离级别REPEATABLE READ语句的默认模式。一致读取不会对其访问的表设置任何锁定,因此其他会话可以在对表执行一致读取的同时自由修改这些表。

  

InnoDBINSERT INTO ... SELECT, UPDATE ... (SELECT)CREATE TABLE ... SELECT等select语句使用一致读取,如果FOR UPDATE未指定LOCK IN SHARE MODEinnodb_locks_unsafe_for_binlog }选项已设置且事务的隔离级别未设置为SERIALIZABLE。因此,在从所选表读取的行上没有设置锁。否则,InnoDB使用更强的锁,SELECT部分的行为类似READ COMMITTED,其中每个一致的读取,即使在同一事务中,也会设置和读取自己的新快照。

相关问题