2012-12-27 44 views
9

我编写一个备份shell脚本来执行mysqldump。如何锁定一个MySQL数据库中的所有表?

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

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

+1

'--lock-tables'应该在转储之前锁定所有要转储的表。是什么让你觉得它没有这样做? – cdhowie

+0

我在MySQL 5.1中测试过,当我在mysqldump中使用--lock-tables时,我仍然可以将数据插入到$ DB_NAME数据库的表中。 – KeepZero

回答

4

你应该看看这个选项。

FLUSH TABLES WITH READ LOCK

关闭所有打开的表和锁与全局读锁定所有数据库中的所有表。这是一个非常方便的方式来获得备份...

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

+0

'具有读锁的刷新表' – Benjamin

+0

这会发出* global *读锁,而不仅仅是单个数据库中的表。 –

6

远远没有最漂亮的解决方案,但这个工作。我有同样的需求,这里是我的解决方案,稍作修改以匹配变量名称。我假设你在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 
+0

您可以从数据库中选择每个表格。这可能比“FLUSH TABLES WITH READ LOCK”更好,它可以锁定所有数据库中的所有表,但是您的解决方案似乎失败,数据库中包含大量表(至少对我而言)。 我通过使用“FLUSH TABLES WITH READ LOCK”(锁定所有数据库上的所有表)并将第一个管道移除到$ MYSQLCMD来更改它。 – OderWat

+0

更新:我用“SET SESSION group_concat_max_len = 8192;”在你的第一个ECHO面前,因为这是造成这个问题的原因! TY为你酷脚本! – OderWat

+0

请注意,如果你喜欢。 –

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 !" 

外壳sleep命令直接确保了mysqldump的开始之前执行运行mysql的锁定命令的后台任务。你可以减少到1秒,它应该仍然很好。将其增加到30秒,然后尝试在这30秒内将值插入另一个客户端的任何表中,您将看到它被锁定。

有2分优势,在使用本手册背景锁定,而不是使用mysqldump选项--single-transaction--lock-tables

  1. 这一切锁定,如果您有混合的MyISAM/InnoDB表。
  2. 您可以在同一锁定期间运行除mysqldump之外的其他命令。例如,在主节点上设置复制时很有用,因为您需要将SHOW MASTER STATUS;作为您创建的转储的确切状态(在解锁数据库之前)获取二进制日志位置,以便能够创建复制从服务器。
+0

即使在备份单个数据库时,这也会在所有数据库中发出* global *锁定。 –

相关问题