如何锁定一个mysql数据库中的所有表?

Posted

技术标签:

【中文标题】如何锁定一个mysql数据库中的所有表?【英文标题】:How to lock all tables in one mysql db? 【发布时间】:2012-12-12 14:30:06 【问题描述】:

我写了一个备份shell脚本来执行mysqldump。

mysqldump -u$BACKUP_USER -p$BACKUP_PASS --flush-logs --lock-tables $DB_NAME > $SQL_FILE

我的数据库的存储引擎是 MyISAM。所以我不能使用--single-transaction 选项。 --lock-tables 在 mysqldump 进程中只锁定一张表。 我的 MySQL 实例中有很多数据库,我不想使用--lock-all-tables,它会锁定我服务器中运行的所有数据库。 那么,如何同时锁定 ONE mysql 数据库中的所有表以便转储它?

【问题讨论】:

--lock-tables 应该在转储表之前锁定所有要转储的表。是什么让您认为它没有这样做? 我在 mysql 5.1 中进行了测试,当我在 mysqldump 中使用 --lock-tables 时,我仍然可以将数据插入到 $DB_NAME 数据库的表中。 【参考方案1】:

你应该研究一下这个选项。

FLUSH TABLES WITH READ LOCK

关闭所有打开的表并使用全局读锁锁定所有数据库的所有表。这是获取备份的一种非常方便的方式...

http://dev.mysql.com/doc/refman/5.0/en/flush.html

【讨论】:

FLUSH TABLES WITH READ LOCK 这会发出 global 读锁,而不仅仅是单个数据库中的表。 问题是针对单个数据库,而不是所有数据库。【参考方案2】:

这就是我的做法。它应该适用于所有情况,因为它使用FLUSH TABLES WITH READ LOCK

#!/bin/bash

DB=example
DUMP_FILE=export.sql

# Lock the database and sleep in background task
mysql -uroot -proot $DB -e "FLUSH TABLES WITH READ LOCK; DO SLEEP(3600);" &
sleep 3

# Export the database while it is locked
mysqldump -uroot -proot --opt $DB > $DUMP_FILE

# When finished, kill the previous background task to unlock
kill $! 2>/dev/null
wait $! 2>/dev/null

echo "Finished export, and unlocked !"

shellsleep命令只是为了确保运行mysql锁定命令的后台任务在mysqldump启动之前执行。您可以将其减少到 1 秒,它应该仍然可以。将其增加到 30 秒,然后尝试在这 30 秒内从另一个客户端的任何表中插入一个值,您会看到它已被锁定。

使用这种手动后台锁定有两个优点,而不是使用mysqldump 选项--single-transaction--lock-tables

    如果您有混合的 MyISAM/InnoDB 表,这会锁定所有内容。 除了mysqldump,您还可以在同一锁定期间运行其他命令。例如,在主节点上设置复制时,它很有用,因为您需要在您创建的转储的确切状态下(在解锁数据库之前)使用SHOW MASTER STATUS; 获取二进制日志位置,以便能够创建一个复制从属。

【讨论】:

这也会对所有数据库发出全局锁,即使您正在备份单个数据库。【参考方案3】:

到目前为止,这不是最漂亮的解决方案,但这很有效。我有同样的需求,这是我的解决方案,稍作修改以匹配您的变量名。我假设您在 Linux 上运行 MySQL,因为这在很大程度上依赖于 shell BASH 语义。如果您使用的是 Windows,这可能无法正常工作。

# Mysql script to lock all tables in one DB
# (such as to get a consistent export dump of one database)

MYSQLCMD="mysql -u$BACKUP_USER -p$BACKUP_PASS -A"

function lock_db 
  [ -e "/tmp/mysql-db-lock-$1" ] && rm "/tmp/mysql-db-lock-$1"
  mkfifo "/tmp/mysql-db-lock-$1"
  (
    (
      echo "SELECT CONCAT( 'LOCK TABLES '
             , GROUP_CONCAT(CONCAT('\`',table_name,'\`'),' WRITE')
             , ';'
             ) AS \"-- Statement to lock tables\"
      FROM information_schema.tables
      WHERE table_schema='$1'
      ORDER BY table_name;
      " | $MYSQLCMD
      echo "\! cat '/tmp/mysql-db-lock-$1' >/dev/null"
      echo 'UNLOCK TABLES;'
    ) | $MYSQLCMD -D"$1"
    rm "/tmp/mysql-db-lock-$1"
  ) &


function unlock_db 
  >"/tmp/mysql-db-lock-$1"


# Lock one database, all tables
lock_db $DB_NAME

# Verify locks have been placed
echo "SHOW OPEN TABLES WHERE in_use != 0" | $MYSQLCMD

# Do whatever here that you needed the locked db for
mysqldump -u$BACKUP_USER -p$BACKUP_PASS $DB_NAME > $SQL_FILE

# Release locks
unlock_db $DB_NAME

# Verify locks released
echo "SHOW OPEN TABLES WHERE in_use != 0" | $MYSQLCMD

【讨论】:

您从数据库中选择每个表。这可能比锁定所有数据库中所有表的“FLUSH TABLES WITH READ LOCK”要好,但您的解决方案似乎因数据库包含大量表而失败(至少对我而言)。我通过使用“FLUSH TABLES WITH READ LOCK”(锁定所有数据库上的所有表)对其进行了更改,并将第一个管道删除到 $MYSQLCMD。 更新:我使用了“SET SESSION group_concat_max_len=8192;”在你的第一个 ECHO 前面,因为这首先是导致问题的原因! TY 给你很酷的脚本! @ Joshua Huber : 如果 --lock-tables 锁定数据库中的所有表,那么它与 'mysqldump' 可用的 --lock-all-tables 标志有何不同。

以上是关于如何锁定一个mysql数据库中的所有表?的主要内容,如果未能解决你的问题,请参考以下文章

如何查看mysql中表的锁定情况

mysql数据备份还原

MySQL数据库锁

Mysql 表锁定的问题

MySQL行表锁定

MySQL 事物控制和锁定语句