去年有段时间公司做了个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 ....
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,那就只能舍弃存储过程了.不过话又说回来,要是这些你都能忍受的话,就真成了忍者了.仁(忍)者无敌.