PDO调用MySQL存储过程报1414错误且登录尝试表未更新问题咨询
问题修复方案
错误根因说明
你遇到的1414报错是MySQL对OUT/INOUT参数的固有要求:存储过程的OUT/INOUT参数只能接收MySQL服务端的会话变量(即@前缀的变量),你直接绑定PDO客户端变量作为INOUT参数传入,服务端无法识别,因此抛出权限/语法错误。
另外返回结果仅用户名正确、其余都是默认值的问题,核心是存储过程里的NULL值比较写法错误,MySQL中不能用!= null判断非空,必须用IS NOT NULL,否则判断结果永远为假,后续赋值逻辑不会触发。
具体修复步骤
1. 存储过程逻辑修复
首先修复空值判断的核心问题,找到存储过程末尾的输出判断逻辑,将:
IF (v_Hash != null) THEN
修改为:
IF (v_Hash IS NOT NULL) THEN
其次修正失败计数的初始值问题,你首次插入失败记录时v_Attempts初始值为0,插入后才更新计数,会导致首次失败的计数取值错误,建议将INSERT部分的Attempts赋值改为:
INSERT INTO users_login_attempts( Username, Attempts, IPAddress, IPGeoLocation) VALUES( v_Username, 1, v_LoginIP, v_IPGeoLocation) ON DUPLICATE KEY UPDATE Attempts = Attempts +1, IPAddress = VALUES(IPAddress), IPGeoLocation = VALUES(IPGeoLocation);
2. PHP调用逻辑修复
放弃直接绑定PDO参数到INOUT位,改用MySQL会话变量传递输出值,执行后单独查询获取返回结果,示例代码如下:
// 调用存储过程,最后一位用MySQL会话变量@ReturnStatus占位 $SP1 = 'call login_authentication(:Username, :LoginIP, :IPGeoLocation, @ReturnStatus)'; $Stmt = $DBConnection->Prepare($SP1); // 绑定三个输入参数 $Stmt->BindParam(':Username', $Name, PDO::PARAM_STR); $Stmt->BindParam(':LoginIP', $LoginIP, PDO::PARAM_STR); $Stmt->BindParam(':IPGeoLocation', $IPGeoLocation, PDO::PARAM_STR); $Stmt->Execute(); // 先拿到存储过程返回的结果集(即你写的SELECT返回的密码哈希或者错误信息) $SP1RS = $Stmt->fetchAll(PDO::FETCH_ASSOC); var_dump($SP1RS); // 如果需要拿INOUT参数v_ReturnStatus的值,额外执行查询获取 $Stmt = $DBConnection->query('SELECT @ReturnStatus as ReturnStatus'); $returnStatus = $Stmt->fetch(PDO::FETCH_ASSOC)['ReturnStatus']; var_dump($returnStatus);
补充说明
如果你不需要通过INOUT参数返回值,完全可以删掉存储过程的v_ReturnStatus INOUT参数,所有返回值都通过SELECT结果集返回,就不用额外处理会话变量,调用逻辑更简单。
内容的提问来源于stack exchange,提问作者PHP Addict
相关产品推荐
相关产品推荐

