У меня есть функция 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.