Применяется ли блокировка строк в подчиненной базе данных к основной базе данных? - PullRequest
0 голосов
/ 15 октября 2018

Например, в транзакции

START TRANSACTION;
SELECT count(*) as count FROM `order` WHERE user_id = 25286 LOCK IN SHARE MODE;
INSERT INTO `order` (`id`, `user_id`, `product_id`) VALUES (NULL, '25286', '36296');

мы выполняем запрос SELECT LOCK IN SHARE MODE;, SELECT будет выполняться в подчиненной базе данных и блокируем строку.

SELECT LOCK IN SHARE MODE также создать блокировку строки в базе данных master, чтобы запрос INSERT не выполнялся в базе данных master?

1 Ответ

0 голосов
/ 15 октября 2018

НЕТ - Блокировка не распространяется на сервер (ы).Таким образом, явная блокировка на подчиненном сервере не блокирует соответствующие таблицы на главном сервере, и наоборот .

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

Я сделал подобный тип фильтрации в PHP-коде.Для направления запросов на соответствующие серверы (чтение запросов на ведомый и запись запросов на ведущий) пишется пользовательская функция для идентификации типа запроса.

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

Кроме того, для Set только SET AUTOCOMMIT и SET TRANSACTION являются командами записи.

Ниже приведена в значительной степени уменьшенная версия фактического кода, который мы используем:

/*
* All the WRITE operation commands
*/
$write_commands = array(
    'create', 
    'alter', 
    'drop', 
    'truncate',
    'comment', 
    'rename', 
    'insert', 
    'update',
    'delete', 
    'merge', 
    'call', 
    'lock', 
    'unlock',
    'start', 
    'commit', 
    'rollback', 
    'savepoint',
    'set', 
    'replace' 
);


/*
* method to determine whether Read or Write
* @param $sql String (SQL query string)
* @return: void
*/
function determineReadOrWrite(string $sql): void {

    $dml_query = false;

    $words = str_word_count(strtolower(trim($sql)), 1);
    $first_word = isset($words[0]) ? $words[0] : '';
    $second_word = isset($words[1]) ? $words[1] : '';

    if (in_array($first_word, $this->write_commands)) {
        /* if it is not "set" then we set to master link */
        if ($first_word !== 'set'
        || ($first_word === 'set' && $second_word === 'autocommit')
        || ($first_word === 'set' && $second_word === 'transaction')
        ) {
            $dml_query = true;

            /* If we Lock tables or Begin a Transaction, we should run on Write servers only */
            /* till we Commit/Rollback or Unlock Tables */
            if(($first_word === 'start' && $second_word === 'transaction') 
            || $first_word === 'lock'){

                /* Set whether the current query is starting a Transaction / Lock etc */
                $this->wait_for_commit_rollback = true;
            }

            /* We are doing Commit/Rollback or Unlock Tables */
            if ($first_word === 'commit' 
            || $first_word === 'rollback' 
            || $first_word === 'unlock') {
                $this->wait_for_commit_rollback = false;
            }
        }
    }

    /* It's a insert/update/delete/etc query - to be run on Write Db only */
    if ($dml_query || $this->wait_for_commit_rollback) { 
        $this->setActiveConnectionToWrite(true);            

    } else {
        $this->setActiveConnectionToRead();
    }

}
...