2012-12-27 10 views
9

Scrivo uno script di shell di backup per eseguire mysqldump.Come bloccare tutte le tabelle in un mysql db?

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

Il mio motore di archiviazione di db è MyISAM. Quindi non posso usare l'opzione --single-transaction. Il --lock-tables blocca solo una tabella in progress mysqldump. Ci sono molti database nella mia istanza MySQL, non voglio usare --lock-all-tables, bloccherà tutti i database eseguiti nel mio server. Quindi, come bloccare tutte le tabelle in un database mysql su sametime, così posso scaricarlo?

+1

'--lock-tables' dovrebbe bloccare tutte le tabelle da scaricare prima di scaricarle. Cosa ti fa pensare che non lo stia facendo? – cdhowie

+0

Ho un test in mysql 5.1, quando uso --lock-tables in mysqldump, posso ancora inserire dati in una tabella del database $ DB_NAME. – KeepZero

risposta

4

Si dovrebbe esaminare questa opzione.

FLUSH TABLES WITH READ LOCK

Chiude tutte le tabelle aperte e chiuse tutte le tabelle per tutti i database con un blocco di lettura globale. Questo è un modo molto comodo per raggiungere i backup ...

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

+0

'TAVOLI DI LAVAGGIO CON BLOCCO LEGGERO' – Benjamin

+0

Questo problema un blocco di lettura * globale *, non solo le tabelle in un singolo database. –

6

non la soluzione più bella in assoluto, ma questo funziona. Ho avuto lo stesso bisogno ed ecco la mia soluzione, leggermente modificata per abbinare i nomi delle variabili. Suppongo che tu stia utilizzando MySQL su Linux, dato che questo si basa molto sulla semantica della shell BASH. Se sei su Windows, probabilmente non funzionerà.

# 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

È possibile selezionare ciascuna delle tabelle dal database. Potrebbe essere meglio di "FLUSH TABLES WITH READ LOCK" che blocca tutte le tabelle in tutti i database ma la tua soluzione sembra fallire con un database che contiene molte tabelle (almeno per me). L'ho modificato utilizzando "TABELLE FLUSH CON BLOCCO LETTURA" (che blocca tutte le tabelle su tutti i database) e rimosso il primo tubo in $ MYSQLCMD. – OderWat

+0

UPDATE: ho usato "SET SESSION group_concat_max_len = 8192;" di fronte al tuo primo ECHO perché era proprio quello che stava causando il problema! TY per te script cool! – OderWat

+0

Per favore, invertire se ti piace. –

2

Ecco come l'ho fatto. Dovrebbe funzionare in tutti i casi poiché utilizza 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 !" 

La shell sleep comando è solo per assicurarsi che l'attività in background eseguendo il comando di blocco mysql viene eseguito prima che il mysqldump inizia. Potresti ridurlo a 1 secondo e dovrebbe comunque andare bene. Aumentalo a 30 secondi e prova a inserire valori in qualsiasi tabella da un altro client durante quei 30 secondi che vedrai che è bloccato.

Ci sono 2 vantaggi nell'utilizzo di questo blocco di fondo manuale, invece di utilizzare i mysqldump opzioni --single-transaction e --lock-tables:

  1. Ciò blocca tutto, se si è mescolato tabelle MyISAM/InnoDB.
  2. È possibile eseguire altri comandi oltre allo mysqldump durante lo stesso periodo di blocco. È utile, ad esempio, quando si imposta la replica su un nodo master, perché è necessario ottenere la posizione del registro binario con SHOW MASTER STATUS; nello stato esatto del dump creato (prima di sbloccare il database), per poter creare uno slave di replica .
+0

Questo genera anche un blocco * globale * su tutti i database, anche quando si esegue il backup di un singolo database. –

Problemi correlati