我得到一个奇怪的结果,其中一个更新方法(http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/data-retrieval-and-manipulation.html#update)调用激活/停用我的mySQL数据库中的站点用户帐户有时不会更新并返回0.这是代码:
$user_id = '198';
$sqlSetStmnt= [ 'activation_code' => NULL, 'active' => 0 ];
$conn = $this->get( 'database_connection' );
try {
$result = $conn->update( 'users', $sqlSetStmnt,[ 'id' => (int)$user_id ] );
}
catch( Exception $e ) {
$error = $e->getMessage();
throw new \Exception( 'update user account data function -- ' .
'error: ' . $error . ' - ' .
'unable to update your account!' );
} // End of catch( Exception ) block.
if( ( $result === FALSE ) || ( $result !== 1 ) ) {
throw new \Exception( 'update user account data function -- ' .
'update return value: ' . $result . ' - ' .
'unable to update your account!' );
} // if( ( $result === FALSE ) || ( $result !== 1 ) ) ...
用户表中有一个 id int(11)列,它是主键,活动 tinyint(1)列,以及 activation_code varchar(40)NULL列。
请注意 $ user_id 变量包含字符串值'198',但在创建 $ sqlSetStmnt 值时会转换为int。
检查用户表格确认用户表格中有一行,其中 id 列值为198时更新电话。
运行更新调用时使用的帐户具有足够的权限来更改行活动和 activation_code 列值。
系统中没有其他用户或访问数据库,因此该行上没有任何锁定。
我使用x-debug检查了代码,并且 $ user_id 和 $ sqlSetStmnt 变量的值已正确设置为我预期的值,即更新方法将> $ result 设置为0,并且更新方法调用没有抛出异常。
顺便说一下,不需要使用变量绑定,因为 $ user_id 和 $ sqlSetStmnt 变量中的值不是由用户输入的,所以没有可能SQL注入或缓冲区溢出。
有没有办法从DBAL获取有关更新方法返回0的原因的信息?
谢谢。
答案 0 :(得分:1)
在解决此问题之前,我改用:
$result = $conn->update( 'users', $sqlSetStmnt, [ 'id' => (int)$user_id ] );
为:
$sqlUpdateStmnt = 'UPDATE `users` SET field = value ' .
'WHERE `id` = ' . $user_id;
$result = $conn->executeUpdate( $sqlUpdateStmnt );
并得到完全相同的结果,其中一些更新将返回0行,当在users表中肯定有一行,其id与$ user_id的值匹配时。
我通过获取现有行来解决这个问题,然后只在set-clause中的字段与表中的相同列不同时才更新行。
这告诉我0返回值并不是没有匹配的行,但是更新的对任何行都没有影响。
所以这个问题不是一个错误,而是对结果的误解。但是,使用update()方法时,如果由于没有匹配的行以及未进行任何更改而确定更新失败的时间,则问题仍然存在。
我最终的解决方案是以预取为代价来解决这个问题,以验证更新是否会影响行。在我的情况下,对于多用户数据库应用程序,预取实际上并不是一个问题,因为在更新尝试进行更改之前,另一个用户可能已删除了要更新的行。但是,如果两个更新方法更清楚地解释了这一点并返回不同的值,那将是很好的:0表示没有受影响的行,FALSE表示没有找到行。