【问题标题】:MySQL Table Locks with Transactions带有事务的 MySQL 表锁
【发布时间】:2014-06-11 07:34:20
【问题描述】:

我想知道有没有办法在不隐式提交事务的情况下锁定 MySQL 表。

假设我有两个表(table_1、table_2),并且我将数据与事务同时插入到这些表中。而且我需要锁定“table_2”,以便其他用户在事务完成之前无法写入/修改“table_2”。我的问题是当我锁定 table_2 时,事务是隐式提交的。是的,我知道 MySQL 文档中对此进行了解释

LOCK TABLES 不是事务安全的,它会隐式提交任何活动的 尝试锁定表之前的事务

我想知道是否有任何其他事务安全的方法来进行表锁定。

这是我的 C# 代码段

MySQLTransaction trans = conn.BeginTransaction();
command.Transaction = trans;
command.CommandText = "INSERT INTO table_1 VALUES ('val1', 'val2')";
command.ExecuteNonQuery();

command.CommandText = "LOCK TABLES table_2 WRITE";
command.ExecuteNonQuery();

command.CommandText = "INSERT INTO table_2 VALUES ('val1', 'val2')";
command.ExecuteNonQuery();

command.CommandText = "RELEASE TABLES";
command.ExecuteNonQuery();

trans.Commit();

在不提交事务的情况下锁定和插入数据到“table_2”有什么想法吗?

提前致谢

【问题讨论】:

  • 您的表使用什么存储引擎?如果他们使用事务引擎(例如 InnoDB),那么您不需要显式锁定您的表:仅在事务中执行插入操作(如您所做的那样)应该确保它们与并发会话隔离。您面临的实际问题是什么?
  • 是的,它是 InnoDB。我想确保在事务完成之前没有人可以读取/修改 table_2。如果某些用户在事务完成之前访问了“table_2”,那么准确性将是一个问题。
  • 不,不会。将您的操作封装在事务中的全部意义是将它们与并发会话隔离:只有在您提交事务时,插入才会对其他会话自动可见 - 直到那时,它们才可见在交易本身。只需删除您的 LOCK TABLESRELEASE TABLES 命令即可。
  • 我需要为事务使用任何隔离级别吗?
  • 所有事务都使用隔离级别。选择的级别只影响从事务外部看到的从内部看到的变化;因此,您可能希望为您的其他事务选择适当的隔离级别 - 默认级别 REPEATABLE_READ 应该足以满足大多数用例。

标签: c# mysql transactions


【解决方案1】:

如果您打算锁定正确的方法来实现您的初衷,请预先锁定两个表:

LOCK TABLES table_1 WRITE, table_2 WRITE
INSERT INTO table_1 VALUES ('val1', 'val2')
INSERT INTO table_2 VALUES ('val1', 'val2')
UNLOCK TABLES

原生 MySQL 提供了这一点(尽管我从未测试过它是否可以通过连接器工作 - 但不明白为什么不这样做。)

一旦你有了锁,就没有人可以插手了。

【讨论】:

    【解决方案2】:

    试试这个,用 C# 写的

    using (var con = new MySqlConnection { ConnectionString = "YourConnectionString" })
            {
                con.Open();
                MySqlTransaction trans = con.BeginTransaction();
                MySqlCommand command = con.CreateCommand();
                try
                {
                    command.CommandText = @"LOCK TABLES table_1 WRITE, table_2 WRITE;
                                            INSERT INTO table_1 VALUES ('val1', 'val2');
                                            INSERT INTO table_2 VALUES ('val1', 'val2');
                                            UNLOCK TABLES;";
                    command.ExecuteNonQuery();
                    trans.Commit();
                }
                catch(MySqlException ex)
                {
                    trans.Rollback();
                    conn.msgErr(ex.Message + " sql query error.");
                    conn.msgErr("Neither record was written to database.");
                }
                finally
                {
                    command.Dispose();
                    trans.Dispose();
                }
    
            }
    

    【讨论】:

      猜你喜欢
      • 2016-03-22
      • 2011-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-06
      • 1970-01-01
      • 1970-01-01
      • 2012-07-23
      相关资源
      最近更新 更多