源码剖析Yii错误 Invalid parameter number: no parameters were bound_SaneFuture的博客-程序员宝宝

技术标签: activerecord  yii  PHP  数据库  源码  

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操作。然而就几千条的数据,就不必在乎其带来的性能影响。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u011042188/article/details/53098740

智能推荐

ubuntu 离线安装makefile_bigzhao_25的博客-程序员宝宝

ubuntu 离线安装makefileubuntu 离线安装makefile到http://ftp.gnu.org/gnu/make/ 下载make 安装包 我下的是make-3.81.tar.gz复制到机器上,解压并进入目录tar -xzvf make-3.81.tar.gzcd make-3.81依次执行以下命令./configure./make check./make inst

解决方案 VS2013error MSB8031: Building an MFC project for a non-Unicode character set is deprecated_ABC我的博客的博客-程序员宝宝

遇到这种问题实际上就是需要安装一个vc_mbcsmfc.exe双击就可安装,如果VS2013已打开,先关闭2013再编译就OK了

mysql 带参数like_关于mysql中的like语句带参数问题_雪小洁的博客-程序员宝宝

一个题目引入:查询与“B1100”银行在同一城市(假设银行名称的第5和第6个字符为城市名称)的其他的银行的名称。表结构:table bankt数据:data bankt这里首先有一个问题,如何获取第五个和第六个字符。采用mysql的substr方法。SUBSTR(str FROM pos FOR len)//str为字符串对象,pos为开始位置(mysql索引从1开始),length表示截取的长度...

黑马程序员--ADO.NET数据库访问技术(二)_qweasdpoc11的博客-程序员宝宝

Windows Phone 7手机开发、.Net培训、期待与您交流! ----------------------通过这几天的学习,下面来把有关数据适配器和数据集方面的知识点总结一下:   一.DataSet 和DataTable:   数据集在ADO.net中的对象是DataSet,DataSet由一个或多个DataTable组成

自定义UIActionSheet_zhou某某的博客-程序员宝宝

UIActionSheet类系IOS开发中实现警告框的重要的类,而在好多应用中,都对它进行了扩展,今天介绍一下自定义风格的UIActionSheet一、自定义CustomActionSheet类CustomActionSheet类继承UIActionSheet,具体的实现如下所示:1)CustomActionSheet.h头文件#import @interface Cust

利用phpExcel实现Excel数据的导入导出(全步骤详细解析)_darlinghqq的博客-程序员宝宝

(一)导入Excel第一,在前台html页面进行上传文件:如:复制代码代码如下:         导入Excel表:           第二,在对应的php文件进行文件的处理复制代码代码如下: if (! empty ( $_FILES ['file_stu'] ['name'] )) {

随便推点

Appium移动自动化测试-环境搭建与简单使用_高大宝呀的博客-程序员宝宝_linux appium自动化测试教程

参考虫师的《Appium移动自动化测试》http://www.cnblogs.com/fnng/p/4540731.html,简单写一下自己使用Appium,包括搭建环境与运行脚本的过程。(主要是在以后再搭环境的时候有个参考哈哈哈)一、安装一堆东西,并且配置环境变量1. JDK、JRE:毕竟Android是由Java语言开发的,所以想开发Android应用首先需要Java环境。...

Unity3D研究院之Unity中连接本地或局域网MySQL数据库(五十九)_守枫竹清的博客-程序员宝宝

转载:http://www.xuanyusong.com/archives/2326/  最近MOMO身心疲惫。。今天是周末在家无聊我还是决定来学习。不知道学什么,就学MySQL吧。本篇主要记录从MySQL安装到局域网内任意机器连接数据库,也算是对自己学习的总结。今天我没用Mac电脑,而是选择Windows,没有别有用心,而是想熟悉一下Windows下操作Unity。官网上下载

RHEL7(centos7)下DNS服务的搭建与配置_Rocl5的博客-程序员宝宝

本文讲述的是RHEL7下DNS服务的搭建与配置,希望能对您有所帮助,由于水平有限,在一些地方肯定有纰漏与不足,还请谅解,写作实属不易,还望支持!

apt-get update 域名无法解析问题_江问的博客-程序员宝宝

apt-get update 域名无法解析问题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与...

关于增强mapper的实现_YinChenLeilei的博客-程序员宝宝_mapperproxy 增强

当我们学习了mybatis后,我们在感叹mybatis的强大的同时,可能也会为重复的sql而感到厌烦,于是有了MybatisPlus 与 TKMybatis,对于还没用过的可能还不习惯,于是便自己想整一个简单的mapper增强,里面放置一些通用的方法,基于MybatisPlus的一些启发来实现,首先不管这些方法在mapper的具体实现,先考虑将这些通用方法在service与mapper层提取出来我们首先定义BaseService与BaseMpper接口:/** * service层公用方法接口

php怎么做图片的跳动,Javascript实现图片轮播:(一)让图片跳动起来!-吴统威的博客_html/css_WEB-ITnose..._叶飞影的博客-程序员宝宝

Javascript实现图片轮播:(一)让图片跳动起来!作者 :towaywu2016-02-16 11:42:53.029 浏览类别 :HTML/CSS/JAVASCRIPT 前端编程 编程语言图片轮播效果,在现在的网站的首页,差不多是必备的效果显示. 所以我从三个方面来讲解这一效果的简单实现. 图片跳动起来图片序列控制的实现前后按钮控制的实现这篇文章来看图片按照间隔时间进行切换.我...

推荐文章

热门文章

相关标签