我有一个PHP脚本,它会产生一个类似于这样的MySQL查询:
INSERT INTO `dailydb`.`probact_actionstaken`(`dispatcher`) VALUES ('kryan');
SET @actionTakenId = LAST_INSERT_ID();
INSERT INTO `dailydb`.`probact_actionstaken_types`(`actionTaken`,`type`)
VALUES
(@actionTakenId, 2);
INSERT INTO `dailydb`.`probact_actionstaken_problems`(`actionTaken`,`problem`)
VALUES
(@actionTakenId, 2);
INSERT INTO `dailydb`.`probact_actionstaken_actions`(`actionTaken`,`action`)
VALUES
(@actionTakenId, 3);
INSERT INTO `dailydb`.`probact_actionstaken_text`(`actionTaken`,`input`,`value`)
VALUES
(@actionTakenId, 3, '7576'),
(@actionTakenId, 4, 'B61'),
(@actionTakenId, 5, '4'),
(@actionTakenId, 6, 'kryan'),
(@actionTakenId, 7, 'test'),
(@actionTakenId, 8, 'testing new debug');
SELECT `index`, `timestamp`
FROM `dailydb`.`probact_actionstaken`
WHERE `index`=@actionTakenId;
(请注意,为了显示此查询,所有值都是:someId
上带有相应值的手动搜索和替换的结果,因为我正在使用预准备语句)
(另请注意,probact_actionstaken
。index
是自动递增的主键,probact_actionstaken
。timestamp
默认为CURRENT_TIMESTAMP
)
查询的目标是插入大量相关数据(基于存储在probact_actionstaken
中的index
。@actionTakenId
的自动值),然后自动返回生成index
和timestamp
以供使用(在使用此输出的AJAX调用中调用脚本)。
此查询大部分都正确执行:五个INSERT
语句都在数据库中插入正确的值。我的问题是最后SELECT
声明。我尝试使用以下PHP代码查看查询结果:
$statement = $dbh->prepare($query);
$statement->execute($params);
$output['results'] = array();
do
{
$output['results'][] = array();
while ( $result = $statement->fetch(PDO::FETCH_ASSOC) )
{
$output['results'][count($output['results'])-1][] = $result;
if ( isset($result['index']) )
{
$output['index'] = intval($result['index']);
}
if ( isset($result['timestamp']) )
{
$output['timestamp'] = $result['timestamp'];
}
}
} while ( $statement->nextRowset() );
echo json_encode($output);
我们的想法是使用do...while
块来查看INSERT
语句的结果,然后获取最终SELECT
语句的结果,该语句存储在我的{ {1}}。
在我的本地计算机上(运行PHP 5.4.4),这非常有效。在具有PHP 5.3.10的服务器上,$output
每次都返回false,因此我只获取第一个行集(由于它来自$statement->nextRowset()
语句而为空)。请注意,实际插入无论如何都能正常工作,当我在phpMyAdmin的SQL功能中运行上面的手动填充查询时,它会返回正确的结果(由插入的索引和时间戳组成的表)。
阅读这些问题,似乎这样的多个语句都是一个坏主意,并且实际上并没有使用真正准备好的语句,我仍然使用默认的模拟预处理语句。所以我可以切换到INSERT
和$dbh->prepare
的单独调用,这将解决我的问题,但我担心竞争条件。服务器正在使用Nginx,许多用户可能同时输入条目。我不希望$statement->execute
返回其他用户的条目,并将这些字段与错误的操作相关联。
在MySQL或PHP中是否有某些原因可以防止竞争条件问题?我可以采取一些措施?或者是否有一种安全的方式来使用多个准备好的语句?如果是后者,它是否可以在PHP 3.5.10中运行?
答案 0 :(得分:1)
我不希望LAST_INSERT_ID()返回其他用户的条目,并将这些字段与错误的操作相关联。
LAST_INSERT_ID()函数仅返回在当前会话中生成的最新ID,而不是另一个MySQL会话。
请参阅http://dev.mysql.com/doc/refman/5.6/en/information-functions.html#function_last-insert-id
生成的ID基于每个连接在服务器中维护。这意味着函数返回给定客户端的值是为该客户端影响AUTO_INCREMENT列的最新语句生成的第一个AUTO_INCREMENT值。此值不受其他客户端的影响,即使它们生成自己的AUTO_INCREMENT值。此行为可确保每个客户端都可以检索自己的ID,而无需关心其他客户端的活动,也无需锁定或事务。
由于竞争条件的可能性,如果不以这种方式限制范围,该功能将毫无用处。
我不知道你在处理PHP 5.3和PHP 5.4之间的多结果查询时所看到的差异的答案。避免多查询被认为是最佳做法。
在您将在生产中部署的开发人员环境中使用相同版本的PHP(以及所有软件)也是明智之举。