Как заблокировать все таблицы в одной базе данных mysql?

Я пишу сценарий оболочки резервного копирования для выполнения 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, он заблокирует все базы данных, запущенные на моем сервере. Итак, как заблокировать все таблицы в ОДНОЙ базе данных mysql одновременно, чтобы я мог ее сбросить?


person KeepZero    schedule 27.12.2012    source источник
comment
--lock-tables должен заблокировать все таблицы для выгрузки перед их выгрузкой. Что заставляет вас думать, что это не так?   -  person cdhowie    schedule 27.12.2012
comment
У меня есть тест в mysql 5.1, когда я использую --lock-tables в mysqldump, я все еще могу вставлять данные в таблицу базы данных $ DB_NAME.   -  person KeepZero    schedule 27.12.2012


Ответы (3)


Не самое красивое решение, но это работает. У меня была такая же потребность, и вот мое решение, слегка измененное, чтобы соответствовать вашим именам переменных. Я предполагаю, что вы используете MySQL в Linux, поскольку он в значительной степени зависит от семантики оболочки 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
person Joshua Huber    schedule 11.09.2013
comment
Вы выбираете каждую из таблиц из базы данных. Это может быть лучше, чем FLUSH TABLES WITH READ LOCK, который блокирует все таблицы во всех базах данных, но ваше решение, похоже, не работает с базой данных, содержащей много таблиц (по крайней мере, для меня). Я изменил его, используя FLUSH TABLES WITH READ LOCK (который блокирует все таблицы во всех базах данных) и удалил первый канал к $ MYSQLCMD. - person OderWat; 24.04.2014
comment
ОБНОВЛЕНИЕ: я использовал SET SESSION group_concat_max_len = 8192; перед вашим первым ECHO, потому что именно это и было причиной проблемы! Т.Ы. для вас классный скрипт! - person OderWat; 24.04.2014
comment
@ Джошуа Хубер: Если --lock-tables блокирует все таблицы в базах данных, то чем он отличается от флага --lock-all-tables, доступного также с mysqldump. - person KGhatak; 16.02.2018

Вот как я это сделал. Он должен работать во всех случаях, поскольку использует 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 предназначена только для того, чтобы убедиться, что фоновая задача, выполняющая команду блокировки mysql, выполняется до запуска mysqldump. Вы можете уменьшить его до 1 секунды, и все будет в порядке. Увеличьте его до 30 секунд и попробуйте вставить значения в любую таблицу из другого клиента в течение тех 30 секунд, когда вы увидите, что оно заблокировано.

Использование этой ручной блокировки фона дает 2 преимущества вместо использования mysqldump параметров --single-transaction и --lock-tables:

  1. Это блокирует все, если вы смешали таблицы MyISAM / InnoDB.
  2. Вы можете запускать другие команды в дополнение к mysqldump в течение того же периода блокировки. Это полезно, например, при настройке репликации на главном узле, потому что вам нужно получить позицию двоичного журнала с SHOW MASTER STATUS; в точном состоянии созданного вами дампа (перед разблокировкой базы данных), чтобы иметь возможность создать подчиненное устройство репликации. .
person Nicomak    schedule 04.03.2016
comment
Это также вызывает глобальную блокировку для всех баз данных, даже если вы создаете резервную копию одной базы данных. - person Stefan Lasiewski; 29.11.2017

Вам следует изучить этот вариант.

FLUSH TABLES WITH READ LOCK

Закрывает все открытые таблицы и блокирует все таблицы для всех баз данных глобальной блокировкой чтения. Это очень удобный способ получить резервные копии ...

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

person frustratedtech    schedule 27.12.2012
comment
Это вызывает глобальную блокировку чтения, а не только таблицы в одной базе данных. - person Stefan Lasiewski; 29.11.2017
comment
Вопрос в одной-единственной базе данных, а не во всех. - person Webomatik; 08.10.2019