2014-01-24 3 views
1

На высоком уровне, что у меня есть это:MySQL - таблицы блокировки или начать транзакцию с триггером

  1. базы данных «мастер» A, который заполняется и управляется Application 1.
  2. ведомому» 'на отдельном хосте, который реплицируется из базы данных «master», используя standard mechanism.
  3. Приложение 2, которое выполняется независимо от Приложения 1 и имеет очень ограниченный доступ только для чтения к базе данных подчиненного устройства и доступ на чтение и запись к своей отдельной базе данных.

И в основном то, что должно произойти, заключается в том, что когда некоторые вещи изменяются в базе данных «slave», приложение 2 должно быть уведомлено, чтобы оно могло проверять содержимое базы данных «подчиненный» и записывать некоторые вещи в свои собственные база данных.

Производительность не вызывает беспокойства, и это приемлемо для блокировки всей базы данных slave, когда это происходит. Важнейшей задачей является обеспечение того, чтобы никакая дополнительная информация не была реплицирована в базу данных «slave», пока Application 2 не выполнит свою задачу. Приложение 2 обращается к базе данных «slave» из сеанса, независимого от сеанса, инициирующего уведомление.

Для достижения этой цели, я следующий триггер:

delimiter // 
CREATE TRIGGER create_report_trigger AFTER UPDATE ON jobs 
     FOR EACH ROW 
       BEGIN 
         DECLARE report_id INT; 
         IF (NEW.status = 7 AND OLD.status != 7) THEN 
           CALL CREATE_REPORT_PROC(NEW.id, @report_id); 
         END IF; 
       END; 
     // 
delimiter ; 

... и так как вы не можете начать транзакцию или заблокировать базу данных внутри триггера, у меня есть следующий процедура:

delimiter // 
CREATE PROCEDURE create_report_proc( 
     IN jobId INT, 
     OUT report_id INT 
) 
     BEGIN 
       START TRANSACTION WITH CONSISTENT SNAPSHOT; 
       SELECT CREATE_REPORT(jobId) INTO report_id; 
       COMMIT; 
     END // 
delimiter ; 

процедура взывает к user-defined function, который использует Libcurl связаться приложения 2 и дайте ему знать, что он должен обработать работа.

Эта процедура отлично работает, когда я вызываю ее вручную в командной строке MySQL. Однако, когда она вызывается из триггера, следующее сообщение об ошибке появляется в журнале MySQL:

Explicit or implicit commit is not allowed in stored function or trigger

... так что, по-видимому MySQL достаточно умны, чтобы обнаружить, что я пытался не подорвать его «нет блокировки изнутри триггера ", используя триггер-делегат для процедуры.

Пользовательская функция ожидает завершения работы приложения 2, прежде чем возвращать результат вызывающему абоненту, что может быть актуальным (если процесс репликации MySQL по существу блокируется выполнением триггера, тогда нет необходимости вручную блокировать ничего, процесс репликации - это единственное, что может внести изменения в базу данных «подчиненный»).

Во всяком случае, я полагаю, есть два вопроса:

  1. Поскольку триггер срабатывает, как следствие обновления, сделанное в процессе репликации MySQL, это означает, что процесс репликации блокируется, пока спусковой крючок возвращается?

  2. Если нет, как заблокировать базу данных или остановить процесс репликации с помощью триггера? Я полагаю, что выдача STOP SLAVE; изнутри триггера может это сделать?

Edit - А вот бонус Followup вопрос:

Когда Application 2 идет делать свое дело, данные, которые он видит, не отражает самую последнюю информацию, которая должна быть в «раба» база данных. В частности, любые обновления, сделанные в таблице jobs как часть триггерной транзакции, не видны для приложения 2.

Почему это так, если триггер сконфигурирован для запуска AFTER UPDATE? И есть ли способ сделать новый контент видимым для приложения 2 в базе данных, или же необходимо вручную собирать и передавать все обновленные значения полей как часть отправленного уведомления?

ответ

2

Итак, на основании моих собственных исследований:

  1. выполнение триггера является синхронным, и блокирует вызывающий поток до тех пор, пока триггер завершится. Репликация MySQL по умолчанию является по существу однопоточными процессами (и я думаю, что даже если вы включаете многопоточную репликацию, вы получаете только один поток на базу данных). Поэтому в моем случае блокирование потока репликации «блокирует» базу данных для всех практических целей; нет никого, кроме потока репликации, у которого есть права на запись.

  2. У вас нет, явно. Однако выполнение триггера считается частью транзакции, вызвавшей его, что означает, что вы можете быть неявно заблокированы/в атомной транзакции в любом случае. Степень, в которой это происходит, по-видимому, зависит от настроек хранилища и настроек изоляции транзакций.

  3. Все еще не совсем уверен в вопросе «бонуса», но я бы предположил, что это связано с №2. Если запуск триггера является частью транзакции, вызвавшей его, то эта транзакция не может быть зафиксирована до завершения триггера. И если транзакция не была выполнена, то наблюдатели на других сеансах не смогут увидеть какие-либо изменения, которые являются ее частью.

    В любом случае передача обновленных полей в качестве параметров в UDF позволила решить эту проблему достаточно хорошо.

Смежные вопросы