Функция MySQL возвращает результат «кэширование» при непосредственном вызове через соединение Doctrine - PullRequest
0 голосов
/ 12 июня 2019

У меня есть функция MySQL, которая используется для нумерации представленных документов. Он реализован непосредственно на сервере MySQL (в значительной степени, чтобы избежать взаимоблокировок, параллелизма и подобных приятных вещей). Таблица хранит последний использованный номер для конкретного ключа документа, и функция берет этот номер, увеличивает его и возвращает обратно в приложение Symfony, которое присваивает его документу.

DELIMITER $$
FUNCTION `NEXT_NUMBER`(requested_key VARCHAR(255)) RETURNS int(11)
BEGIN
    DECLARE nextNumber INT;

    INSERT INTO `document_numbers` (key, last_number) VALUES (requested_key, 1)
        ON DUPLICATE KEY UPDATE last_number = last_number+1;
        SELECT last_number INTO nextNumber FROM `document_numbers` WHERE key = requested_key

   RETURN nextNumber;
END$$
DELIMITER ;

В приложении эта функция вызывается в отдельном соединении Doctrine, которое не используется для стандартных операций над сущностями и базами данных.

public function getNewNumber(string $key) : int
{
    $this->connection->setAutoCommit(false);

    try {
        $this->connection->beginTransaction();
        $statement = $this->connection->prepare("SELECT NEXT_NUMBER(:key);");
        $statement->bindValue('series', $key);
        $statement->execute();
        $this->connection->commit();

        $number = (int) $statement->fetchColumn();

        $this->connection->close();
    } catch (\Throwable $e) {
        $this->connection->rollBack();
        $this->connection->close();
        throw $e;
    }

    return $number;
}

Теперь проблемная часть в том, что

$number = (int) $statement->fetchColumn();

возвращает одно и то же значение для нескольких HTTP-запросов. Практически такое же поведение, как если бы значение результата было кэшировано. Такое поведение не повторяется 100% времени. Я пытался добавить SQL_NO_CACHE к SELECT запросу безрезультатно.

Настройка:

  • MySQL 5.7
  • Symfony 3,4
  • PHP 7.1
  • Doctrine / DBAL 2.7
  • OroPlatform 3.1

Конфигурация доктрины:

doctrine:
    dbal:
        default_connection:   default
        connections:
            default:
                server_version: '5.7'
                driver:       "%database_driver%"
                host:         "%database_host%"
                port:         "%database_port%"
                dbname:       "%database_name%"
                user:         "%database_user%"
                password:     "%database_password%"
                charset:      UTF8MB4
                mapping_types:
                    bit: boolean
                    json: string
            secondary: # this one is used for $this->connection->prepare("SELECT NEXT_NUMBER(:key);");
                server_version: '5.7'
                driver:       "%database_driver%"
                host:         "%database_host_secondary%" # this is simply pointing to 127.0.1.1
                port:         "%database_port%"
                dbname:       "%database_name%"
                user:         "%database_user%"
                password:     "%database_password%"
                charset:      UTF8MB4

Нет настроек кэширования MySQL / Doctrine.

1 Ответ

0 голосов
/ 12 июня 2019

Таким образом, одно из решений состоит в том, чтобы снова включить автоматическую фиксацию на $this->connection->setAutoCommit(true);, хотя это определенно не тот случай, когда был такой же кусок кода на Symfony 2.8 и в предыдущей версии Doctrine.

Также "SELECT NEXT_NUMBER(:key);" на самом деле возвращал увеличенное число, а не какую-то «кэшированную» версию, но не фиксировал ее в таблице базы данных после того, как она была увеличена.

Я не знаю, как это происходило, поскольку $this->connection->commit(); явно выполняется ине выдает никаких ошибок.Может быть, MySQL / PHP / Doctrine каким-то образом создает отдельную транзакцию для операции.Тем не менее, до сих пор, похоже, не возникало никаких проблем с включенной автоматической фиксацией, поэтому сам вопрос, вероятно, решен, хотя любые входные данные и описание поведения приветствуются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...