我有一个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
查询中。
设置:
文档配置:
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缓存设置。
答案 0 :(得分:0)
因此,一种解决方案是重新启用$this->connection->setAutoCommit(true);
上的自动提交功能,尽管在Symfony 2.8和早期版本的Doctrine上使用相同的代码绝对不是这种情况。
此外,"SELECT NEXT_NUMBER(:key);"
实际上正在返回递增的数字,而不是某些“缓存”版本,但是在递增之后没有将其提交到数据库表中。
我不知道这是怎么发生的,因为$this->connection->commit();
被清楚地执行并且不会引发任何错误。也许MySQL / PHP / Doctrine以某种方式为该操作创建了独立的事务。但是,到目前为止,自动提交功能似乎还没有遇到任何问题,因此尽管可以对行为进行任何输入和描述,但问题本身也可能得到解决。