惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - Franky
N
Netflix TechBlog - Medium
宝玉的分享
宝玉的分享
Google DeepMind News
Google DeepMind News
腾讯CDC
G
Google Developers Blog
Martin Fowler
Martin Fowler
Microsoft Security Blog
Microsoft Security Blog
Recent Announcements
Recent Announcements
爱范儿
爱范儿
Engineering at Meta
Engineering at Meta
Microsoft Azure Blog
Microsoft Azure Blog
A
About on SuperTechFans
aimingoo的专栏
aimingoo的专栏
有赞技术团队
有赞技术团队
Jina AI
Jina AI
人人都是产品经理
人人都是产品经理
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
M
MIT News - Artificial intelligence
罗磊的独立博客
博客园 - 三生石上(FineUI控件)
美团技术团队
WordPress大学
WordPress大学
阮一峰的网络日志
阮一峰的网络日志

博客园 - 兵

C#异常处理的方式 CryptoAPI与.NET数字签名类的交互问题 Firefox中Iframe的blur与focus事件问题 .NET中几种基本的线程同步方法 为什么说WinForm的控件只能在主线程中创建和调用 C#与Native C++互相访问 PHP5中的引用 Framework里某些类型成员方法的一点疑惑 发现一个FireFox的问题 C#中COM操作(二)---接口查询 C#中COM操作(一)---实例化 非弹出式的模态对话框的背景遮罩 DOTNET事件拾遗 CSS开发辅助工具:Internet Explorer Developer Toolbar 另外一种高效地判断奇数和偶数的方法 如何利用客户端缓存对网站进行优化? 一个多表查询引出的问题(2) 类的成员初始化顺序 一个多表查询引出的问题(1)
Windows版的PDO太衰了
· 2008-08-18 · via 博客园 - 兵

        去年有段时间公司做了个PHP的项目,做了半年的PHP.当时用到的是PHP5.1.6版的,那个时候就发现了Windows版PHP中的PDO不支持一次返回多个查询结果,也就是PDOStatement的nextRowset不能正确执行,给的提示说是什么这是个可有可无的特性,这里没有实现(我faint).但是在Linux上的同样版本号的方法却能正常执行,一般来说我们大都是在Windows下开发,布署的时候在LINUX上,这对于实际运行到没有太大的影响,(虽说PHP的屁股是坐在LINUX这边的,可是为了顶LINUX也不至于用这种手段吧).

        那个时候上官网论坛查了一下,有N多人把这个提为BUG,(也包括在下,呵呵),希望在以后的版本中实现.过了一年多了,现在PHP的最新稳定版本到5.2.6了,据说是修改了之前N多的BUG.最近刚好我有空,也想把以前丢掉的PHP捡回来,顺便也想看看以前的那个"可有可无的特性"到底有没有实现.于是就整了这个最新的版本,一阵测试后结果还是令人失望,新的版本来是继承了以前的特性,这个nextRowset下是不能正常执行下去.哎,看来PHP的团队是不打算在Windows版里面实现这个特性了,至少是最近一段时间不打算实现.想要在Windows下面布署的PHPer们只能分多次查询来得到多个查询结果了.虽然这样也能达到目的,但是本来可以执行一次SQL就返回的现在得整到多个查询里面去执行,怎么看也觉得别扭,而且增加了IO该问次数,效率肯定不如一次查询返回多个结果的方式.

        如果"一次查询返回多个结果集"还算是一个可选特性的话,那么接下来的这个问题我认为就算是一个比较严重的BUG了.昨天我在试PDO调用Mysql的存储过程的时候怎么执行都会报错

PDOException: SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. in ....

 1 $conn = new PDO($connString, $user, $pass);
 2 
 3 $conn->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
 4 $conn ->query('SET NAMES utf8');
 5 
 6 // 执行成功:
 7 $stmt = $conn->prepare('CALL test();');
 8 $stmt->execute();
 9 $result = $stmt->fetch();
10 
11 
12 
13 $stmt = $conn->prepare('select * from Test');
14 // 执行失败,拿掉上面存储过程那块就成功
15 $stmt->execute();
16 

     情况是这样的,我在一个连接上调用了一个存储过程查询并返回一条记录,然后再执行一个普通的查询SQL语句,这个时候就出错了.因为结果就一条数据,所以就使用fetch方法来获取,没有使用fetchAll方法,难道是这个地方造成的?于是我又把代码改了一下,改成了用fetchAll方法来获取结果集,可是错误还是照样出现,在构造PDO的时候设置了PDO::MYSQL_ATTR_USE_BUFFERED_QUERY标识也不行. 又修改了几次代码,并试了好几种情况,得出以下规律:

1.使用PDO的开启事务方法,调用存储过程后,在commit或rollback的时候必出错,但是直接运行SQL语句不会出错

2.不使用PDO的开启事务的方法,调用存储过程与其它查询放在一起,存储过程最后执行,都不会出错

3.在没开启事务的时候,存储过程最后执行,不管使用fetch或都是fetchAll方法都不会出错

4.存储过程与其它查询混在一个连接中执行,存储过程不是最后一个执行,之前的(包括存储过程本身)的执行都不会出错,但是存储过程之后的执行的查询,不管是什么都会出错

以上都是使用php_pdo_mysql的时候出现的,其它的数据库驱动暂时没有测试.看来所有出错的地方都是和存储过程相关的,也就是说同一次连接在存储过程之后不能再有其它的查询(mysql事务的commit和rollback本质上也是调用的sql语句).难道说存储过程的执行就是上面所说的"unbuffered queries",而且还是active的?顺着这个思路报着试一试的心态,我再次在每个Statement使用完后都调用了closeCursor方法,结果仍然是出错.这时候我想到以前nextRowset的经验,难道这又是一个Windows版的"可选特性"?网上Google了一下,果然发现很多朋友都遇到了我这个问题,而且只是在Windows下面出现,Linux版本不会出现这个问题.我真的是无语了.PHP真是力挺Linux呀.以前遇到的那个还可以用迂回方法,多次查询返回结果,这次遇到的这个问题根本是致命的:存储过程不能在其它查询之前执行,一个连接上只能执行一次存储过程,存储过程不能放到事务中执行(这个杀伤力最大).

        好在我们一般都只是在Windows下开发,布署在Linux下,这个到是影响不大.Windows版的PHP要想使用PDO或都说想使用pdo_mysql的驱动,一个字----"难"呀.谁知道还有多少隐藏的没有实现的"可先择的特性"呢?如果还是想要在Windows下面使用PHP的PDO,那就只能舍弃存储过程了.不过话又说回来,要是这些你都能忍受的话,就真成了忍者了.仁(忍)者无敌.