2012-12-27 49 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 *鎖定。 –

相關問題