源码剖析Yii错误 Invalid parameter number: no parameters were bound
2016-11-09 13:20
459 查看
ActiveRecord使用的一个陷阱导致 Invalid parameter number: no parameters were bound
请看下面的例子$criteria = new CDbCriteria(); $criteria->select = "*"; $model = Biubiu::model(); $ids = range(160,163); $criteria->addInCondition("id", $ids); $model->findByPk(160);//某次操作 sleep(32);//处理其他事情花费了较长时间。 $result = $model->findAll($criteria);<1> //$result = $model->getCommandBuilder()->createFindCommand($model->getTableSchema(),$criteria)->queryAll();<2> if($result){ echo count($result); }
为了体现这个问题,我的本地数据库wait_timeout = 30
那么会出现下面的问题:
exception 'Exception' with message 'exception 'CDbException' with message 'CDbCommand failed to execute the SQL statement: SQLSTATE[HY093]: Invalid parameter number: no parameters were bound. The SQL statement executed was: SELECT * FROM `t_biubiu` `t` WHERE id IN (:ycp0, :ycp1, :ycp2, :ycp3). Bound with :ycp0=160, :ycp1=161, :ycp2=162, :ycp3=163' in E:\xxxx\framework\db\CDbCommand.php:569 Stack trace: #0 E:\xxxx\framework\db\CDbCommand.php(578): CDbCommand->queryInternalAll('fetchAll', Array, Array) #1 E:\xxxx\framework\db\CDbCommand.php(418): CDbCommand->queryInternal('fetchAll', Array, Array) #2 E:\xxxx\framework\db\ar\CActiveRecord.php(1356): CDbCommand->queryAll() #3 E:\xxxx\framework\db\ar\CActiveRecord.php(1475): CActiveRecord->query(Object(CDbCriteria), true) #4 E:\xxxx\experiment\protected\commands\YiiCommand.php(18): CActiveRecord->findAll(Object(CDbCriteria))
我的另一片文章和这个问题的原因都是一样的:Yii 数据库重连告别General error: 2006 MySQL server has gone away
以我所见的解决方法就是 :
1—— 尽量避免上面的这种写法,直接addInCondition,把id填入SQL
$criteria->addCondition("id in (". join(",",$ids) . ")");
2——就是重连。
分析:
并不是参数没有绑定,查看findAll()的源码public function findAll($condition='',$params=array()) { Yii::trace(get_class($this).'.findAll()','system.db.ar.CActiveRecord'); $criteria=$this->getCommandBuilder()->createCriteria($condition,$params); return $this->query($criteria,true); }
query实际上执行的是:
$command=$this->getCommandBuilder()->createFindCommand($this->getTableSchema(),$criteria); $command->queryAll();
而createFindCommand()
调用bindValue(),里面的代码如下:
$this->_statement->bindValue($name,$value,$this->_connection->getPdoType(gettype($value)));
连接已经timeout,失效了。bindValue无用。
queryAll() --> queryInternal('fetchAll',PDO::FETCH_ASSOC,[]); -->三次调用 queryInternalAll('fetchAll',PDO::FETCH_ASSOC,[])
简化的queryInternalAll如下:
private function queryInternalAll($method,$mode,$params=array()) { $params=array_merge($this->params,$params); try { $this->prepare(); @$this->_statement->execute(); { $mode=(array)$mode; call_user_func_array(array($this->_statement, 'setFetchMode'), $mode); $result=$this->_statement->$method(); $this->_statement->closeCursor(); } return $result; } catch(Exception $e) { $errorInfo=$e instanceof PDOException ? $e->errorInfo : null; $message=$e->getMessage(); if(YII_DEBUG) $message.='. The SQL statement executed was: '.$this->getText().$par; if(!empty($errorInfo) && (2006 == $errorInfo[1] || 2013 == $errorInfo[1])) { $this->_connection->setActive(false); $this->cancel(); } throw new CDbException(Yii::t('yii','CDbCommand failed to execute the SQL statement: {error}', array('{error}'=>$message)),(int)$e->getCode(),$errorInfo); } }
这样就看到了
exception ‘Exception’ with message ‘exception ‘CDbException’ with message ‘CDbCommand failed to execute the SQL statement: SQLSTATE[HY093]: Invalid parameter number: no parameters were bound. The SQL statement executed was:
另外:设置db属性:
'attributes' => [ PDO::ATTR_TIMEOUT => 600, ],
是没有用处的。
但可以考虑使用:
Yii::$app->db->createCommand('SET SESSION wait_timeout = 28800;')->execute();
重试机制:
//Biubiu::getDb()->close(); 这么搞也行但是每次都会关闭。 do{ try{ $result = Biubiu::find()->select("id,value")->where(['id'=>$ids])->all(); foreach ($result as $one){ echo $one->id . ">" .$one->value . PHP_EOL; } }catch (\yii\db\Exception $e){ Biubiu::getDb()->close(); Biubiu::getDb()->open(); if(strpos($e->getMessage(), 'MySQL server has gone away')===false){ throw new Exception($e); } } }while(--$retry);
执行时间较长的脚本,并且一段时间就会结束的,不能用持久化连接
PDO::ATTR_PERSISTENT => true,适合用这种做法进行重连,能有效防止闪断等超时错误。
前面提到的文章给出的解决办法并不适合大量反复的数据库访问,会多很多不必要的ping操作。然而就几千条的数据,就不必在乎其带来的性能影响。
相关文章推荐
- PDO版本问题 Invalid parameter number: no parameters were bound
- 出现Invalid parameter number: no parameters were boundStack
- PDO版本问题 Invalid parameter number: no parameters were bound
- 关于在.NET中通过Parameter方式插入Oracle数据的错误提示——Oracle-ORA-01722 invalid number
- 未重新服务器而导致的错误java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is
- php pdo错误:SQLSTATE[HY093]: Invalid parameter number: parameter was not defined
- ThinkPHP5更新数据遇到SQLSTATE[HY093]: Invalid parameter number: mixed named and positional parameters
- Invalid parameter number: number of bound variables does not match number of tokens
- mybatis错误Parameter index out of range (1 > number of parameters, which is 0)
- Mybatis错误:Parameter 'XXX' not found. Available parameters are [1, 0, param1, param2]
- 处理编译错误"0" is an invalid value for the "DebugInformation" parameter of the "DCC" task.
- 解决ava.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0)类似问题
- SQLException: Parameter index out of range (3 > number of parameters, which is 2).
- Yii 提示Invalid argument supplied for foreach() 等错误
- Invalid number format for port number(链接ORACLE时忘记加端口出现的错误)
- msvcr90.dll!_invalid_parameter_noinfo() Line 125 + 0xc bytes 的排错
- Yii源码阅读笔记 - 错误/异常处理
- 使用mybatis执行sql的时候为什么会出现Parameter index out of range (1 > number of parameters, which is 0)?
- 无法定位程序输入点_invalid_parameter_noinfo_noreturn于动态链接库 MSVCR100.dll上
- Parameter index out of range (1 > number of parameters, which is 0).] with r