关于Zend_Db_Adapter_Pdo_Mssql最后一分页问题的解决方法
January 05, 2009
Zend framework (我当前使用的版本是1.5) 中的MSSQL(SQL SERVER)PDO Adapter(Zend_Db_Adapter_Pdo_Mssql)分页是有问题的,多数情况最后一页总会和n-1页的记录重叠,经测试Zend Framework 1.7.0里面的Zend_Db_Adapter_Pdo_Mssql同样存在此问题
当有LIMIT的时候,分析ZF_DB生成的SQL语句:
SELECT * FROM ( SELECT TOP 30 * FROM ( SELECT TOP 60 "package_id", "title_eng" FROM "hotel_package" ORDER BY "package_id" DESC ) AS inner_tbl ORDER BY "package_id" ASC ) AS outer_tbl ORDER BY "package_id" desc
上面的SQL是PAGE=2,是每页30笔记录,30就相当于MYSQL中的LIMIT,60就是OFFSET
看不懂上面的SQL的话可参考这里:
http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html
Zend_Db_Select中limitPage方法中有如下代码:
$this->_parts[self::LIMIT_COUNT] = (int) $rowCount; $this->_parts[self::LIMIT_OFFSET] = (int) $rowCount * ($page - 1);
显然,这个SQL的结果是每一页都是30笔,最后一页也是。
当 “hotel_package” 中有31笔记录的时候,一共有2页,翻到第2页的时候也显示30条记录是不对的
当然这不太影响使用,但是挑剔的人会提出质疑,这也无可厚非,但是怎么ZEND也不重视这个问题
或者说ZEND并不重视ZF中的MSSQL
由于ZF本身的问题,所以不得不修改ZF的代码,这种情况是在万不得已经的情况下才去做…
首先考虑是修改 Zend_Db_Adapter_Pdo_Mssql 这个类,因为是Adapter所以可以自己另存一个,改一下类和文件名,是最好的方法并不影响到ZF以后的升级更新,不过另存修改Zend_Db_Adapter_Pdo_Mssql并不现实,因为传给limit的参数有限:
limit($sql, $count, $offset = 0)
没法判断是否最后一页是否小于limit,没办法,只能把目光转移到Zend_Db_Select中的limitPage
修改如下:
public function limitPage($page, $rowCount, $tail = NULL)
if ($tail > 0 && !is_bool($tail)) {
$this->_parts[self::LIMIT_COUNT] = (int) $tail;
}else {
$this->_parts[self::LIMIT_COUNT] = (int) $rowCount;
}
然后在自己的分页类中,添加一个tail的返回值
// pagerInfo 保存关于分页信息的数组
$pagerInfo['_tail'] = NULL;
// 判断是否最后一页
if ($page == $pagerInfo['pagesCount']) {
// 获取余数
$tail = $rows_count % $rowCount;
if ($tail != 0) $pagerInfo['_tail'] = $tail;
}
在目前最新的Zend Framework 1.7.0 中增加这样这两个特性
Zend_Db_Table_Select adapater for Zend_Paginator
Support for custom adapters in Zend_Paginator
看来是一个分页功能,不知道是怎样处理上面的问题的,下次再去了解一下





