(二)关于ThinkPHP2.1版本操作MSSQL类的BUG--selec查询只得出1条记录
BUG:Model类的select方法默认只返回1条记录
TP的手册中写的是select方法返回的是全部的记录,但我在实际操作中,返回的只有1条记录,我们再次进行源码的分析。
(1)Action中的代码如下:
- $operaInfo = new Model("tbloperainfo");
- $list = $operaInfo->select();
(2)根据代码我们进入Model类的select方法,在select方法中又调用了Db类的select方法:
- $resultSet = $this->db->select($options);
(3)select方法中有如下的代码片段,对查询的sql进行了处理:
- $sql = str_replace(
- array('%TABLE%','%DISTINCT%','%FIELDS%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%'),
- array(
- $this->parseTable($options['table']),
- $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false),
- $this->parseField(isset($options['field'])?$options['field']:'*'),
- $this->parseJoin(isset($options['join'])?$options['join']:''),
- $this->parseWhere(isset($options['where'])?$options['where']:''),
- $this->parseGroup(isset($options['group'])?$options['group']:''),
- $this->parseHaving(isset($options['having'])?$options['having']:''),
- $this->parseOrder(isset($options['order'])?$options['order']:''),
- $this->parseLimit(isset($options['limit'])?$options['limit']:'')
- ),$this->selectSql);
- $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false);
- return $this->query($sql);
在处理的时候调用了parseLimit方法,由于面向对象的多态性,这个方法应该是在DbMssql中的parseLimit方法。我们看下该方法的参数:isset($options['limit'])?$options['limit']:'' 这个表达式结果应该为空字符串'',因为我们在调用Model类的select方法的时候没有传任何参数。
我们进入DbMssql看下代码如下:
- public function parseLimit($limit) {
- if(empty($limit)) $limit=1;
- $limit = explode(',',$limit);
- if(count($limit)>1)
- $limitStr = '(T1.ROW_NUMBER BETWEEN '.$limit[0].' + 1 AND '.$limit[0].' + '.$limit[1].')';
- else
- $limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")";
- return $limitStr;
- }
(4)在parseLimit方法中,第一步将$limit赋值为1;第二部将$limit拆分为数组;第三部判断数组的元素个数后执行了如下的代码:
$limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")";
在这里我们可以看出$limitStr的具体值为:'(T1.ROW_NUMBER BETWEEN 1 AND 1)'
好,我们继续跟踪源码。
(5)第3步对$selectSql处理后,调用了DbMssql类的query方法,在该方法中又调用了getAll方法将查询的结果存入$result数组,紧接着将$result一层层返回。
(6)好,到此为止执行流程已经全部结束。我们看下具体执行的SQL,如下:
- SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER ( ORDER BY agentid) AS ROW_NUMBER FROM (SELECT * FROM tblagentinfo) AS thinkphp) AS T1 WHERE (T1.ROW_NUMBER BETWEEN 1 AND 1)
看下执行的SQL,发现引起这个BUG的原因就是: (T1.ROW_NUMBER BETWEEN 1 AND 1) 这个SQL片段。
(7)原因找到了,该如何处理呢?
我们肯定是在DbMssql类的parseLimit方法下手,因为我们需要查询所有的记录,因此该方法返回的值最好是为 '' 。我们将parseLimit方法的第一行代码修改为如下的代码:
- if(emptyempty($limit)) {
- return $limit;
- }
就是如果$limit为空,直接返回。修改后刷新下页面发现报错了,看了执行的SQL如下:
- SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER ( ORDER BY agentid) AS ROW_NUMBER FROM (SELECT * FROM tblagentinfo) AS thinkphp) AS T1 WHERE
发现SQL到WHERE关键字就没了,我们看下DbMssql中$selectSql的定义:
- protected $selectSql = 'SELECT T1.* FROM (SELECT ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER, thinkphp.* FROM (SELECT %DISTINCT% %FIELDS% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%) AS thinkphp) AS T1 WHERE %LIMIT%'
再结合parseLimit方法中的代码,具体处理方法如下:
1.将SQL中的WHERE删掉
2.在parseLimit中将代码修改如下:
- if(count($limit)>1)
- $limitStr = ' WHERE (T1.ROW_NUMBER BETWEEN '.$limit[0].' + 1 AND '.$limit[0].' + '.$limit[1].')';
- else
- $limitStr = ' WHERE (T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")";
即是将WHERE直接放到$limitStr中,这样就OK了。
转载于:https://blog.51cto.com/shane/778063
(二)关于ThinkPHP2.1版本操作MSSQL类的BUG--selec查询只得出1条记录相关推荐
- discuz mysql类_Discuz X2二次开发之数据库操作 DB类
Discuz X2的数据库操作类主要包括以下几个: DB::result_first 返回SQL查询的唯一字段的唯一值,查询结果是字符 DB::fetch_first 返回SQL查询的多个字段的值,查 ...
- MSSQL分组取后每一组的最新一条记录
数据库中二张表,用户表和奖金记录表,奖金记录表中一个用户有多条信息,有一个生效时间,现在要查询: 奖金生效时间在三天前,每个用户取最新一条奖金记录,且用户末锁定 以前用的方法是直接写在C#代码中的: ...
- Mysql数据库基本知识二:表的基础操作
=================================[建表]============================== 分三部分: 1.指定表名 2.定义列(),列名 数据类型 约束 ...
- php实现分页mssql,PHP操作mssql数据库类,含分页类[分页类原创]
/** * PHP操作mssql数据库类,含分页类 * Enter description here ... * @author aboc 9986584 2011-04-09 * */ class ...
- Linux常用基本命令详解(二)-------磁盘分区和磁盘管理类命令
Linux常用基本命令详解(一) Linux常用基本命令详解(二)-------磁盘分区和磁盘管理类命令 Linux常用基本命令详解(三) 1.磁盘分区 磁盘分区(系统分区)是使用分区编辑器(part ...
- 新酷卡 mysql接口_新酷卡M池二次开发模块数据库操作版
有大神发了一个soket方式的,尝试继承到模块后发现soket不太适合放到易模块类内, 客户组件不支持放在类内,必须放在界面上,传入赋值类内客户变量,收到数据事件也没办法放在类内,放弃 远程服务支持库 ...
- HBase学习之路(二):Java客户端的CRUD操作详讲
内容简介 一.概述 二.操作前的准备 三.put操作 1.单行put方法 2.使用Put列表 四.get操作 1.单行get方法 2.使用Get列表 五.delete操作 1.单行delete方法 2 ...
- VSTO Office二次开发PPTRibbonX命令操作及对象添加
VSTO Office二次开发PPTRibbonX命令操作及对象添加 本篇分享对于Power Point中一些命令的操作和对于一些比较常用对象.特殊对象的添加功能. 对于Power Point命令操作 ...
- PHP数据库操作分页类
MySQL数据库操作类: 1 <?php 2 class mysql { 3 private $db_host; //数据库主机 4 private $db_user; //数据库用户名 5 p ...
- 封装SQLDMO操作的类
封装SQLDMO操作的类,能完成常用的SQL Server 2000管理工作. 使用前请添加 "Microsoft SQLDMO Object Library" COM 引用. 有 ...
最新文章
- ORA-12514 监听程序当前无法识别连接描述符中的服务
- python参考手册--第8章
- UDP千兆以太网FPGA_verilog实现(四、代码前期准备-UDP和IP协议构建)
- 听说,高手都用记事本写C语言代码?
- 程序员接私活的几个平台
- CPU负载均衡之EAS
- 三维点云配准 matlab,一种基于保局PCA的三维点云配准方法与流程
- BT5R3安装及汉化
- MAX30102 血氧调试笔记
- 颜色名称及色样表(HTML版)
- 【Analytics Kit】【FAQ】集成华为分析服务问题集合 SDK初始化失败/应用调试界面没有数据/常见错误提示
- 微信存储服务器,微信缓存指的是什么?
- 计算机管理下的打印机参数设置,提高办公效率 11种方法设置打印参数
- 借势氢能源发展热潮,重塑股份持续加速行业布局
- 2015062602 - 星际迷航.红杉书评
- CDH安装指南——酒仙网技术
- 母亲节板报图片计算机方案,母亲节电子手抄报图片大全
- 冲压模具中的回弹解决办法
- Java进阶学习第八天——WEB入门
- 支付宝APP支付申请
热门文章
- 认识以及安装redis
- Dynamics 365 Online-Unified User Interface
- (最短路)17bupt新生赛——F. ch追妹
- 自定义Angular服务
- Java 反射机制浅析
- .net System.IO之Stream的使用详解
- 24点游戏算法python_24点游戏算法
- 算法 判断多个点是否在同一圆周线上_广州灵活计费自动出盘机技术方案大盘点...
- android can为啥能发收不到数据_大数据显示:报读MBA已是未来竞争力提升的必然趋势...
- Nginx服务器中的Socket切分,需要的朋友可以参考下