ThinkPHP调用存储过程不能返回结果集的解决方案 转

感谢这篇文章,解决了问题。https://blog.csdn.net/cyd1919/article/details/8859898

对于逻辑比较复杂的增删改差来说,个人认为ThinkPHP的查询语句,连贯操作是不能满足要求的。同样,熟悉存储过程的朋友们更加倾向于用存储过程来替代多次的增删改查操作,或者用以PHP代码实现。

我是一个php的菜鸟,从java转型过来两个礼拜,刚接触thinkphp。所以有任何犯二的地方,希望大家谅解,我仅仅只是希望能够帮助到大家。好了,不废话。直接讲需求,上代码。

表1张:

这个是一个公司部门表,是一个自关联的,与上级部门关联的是fatherId字段;level表示部门级别。

数据:

需求:按照公司组织结构将此表排序。如:

1(级部门)

2    |    2

3 3 3 | 3 3 3

其组织结构是如此,那么排序的输出就按照数据结构中的先根遍历。

效果如:

要达到这样的效果,小弟实在用简单sql语句无法实现,于是就用了存储过程(稍后奉上)。

于是问题出现了。看代码:

上面注释掉的是php代码的原生调用,是可以实现存储过程调用的。但是mysql_fetch_assoc()函数,不消说,只能获取一行结果,虽然加上循环,可行,但这个并不能满足小弟的小小心愿,用了TP为什么还要用原生代码?不爽。

模板代码很简单:

    <ul style="list-style: none">
<volist name="list" id="item">
<li>部门名称:{$item.name};部门描述:{$item.description}</li>
</volist>
</ul>

好吧,问题就是,我用

$dept  = M('Department');
$sql = 'call orgTree()';
$list = $dept->query($sql);
$this->list = $list;
$this->display();

这段代码根本就无法对模板赋值,原因就在于这个$list它是false,单步调试的结果。

然后小弟各种网上查询,在Thinkphp的官网讨论区中看到了一系列不能实现的帖子,大家纷纷吐槽。

好吧,我说重点。不扯野棉花。

单步调试跟中代码,$dept->query($sql);实际就是thinkphp/Lib/Core/Model.class.php中的方法:


/**
* SQL查询
* @access public
* @param string $sql  SQL指令
* @param mixed $parse  是否需要解析SQL
* @return mixed
*/
public function query($sql,$parse=false) {
if(!is_bool($parse) && !is_array($parse)) {
$parse = func_get_args();
array_shift($parse);
}
$sql  =   $this->parseSql($sql,$parse);
return $this->db->query($sql);
}

继续走:$this->db->query($sql);这个到了哪里呢?

thinkphp/Lib/Driver/Db/DbMysql.class.php文件中的 query方法

   /**
* 执行查询 返回数据集
* @access public
* @param string $str  sql指令
* @return mixed
*/
public function query($str) {
//         if(0===stripos($str, 'call')){ // 存储过程查询支持
//             $this->close();
//         }
$this->initConnect(false);
if ( !$this->_linkID ) return false;
$this->queryStr = $str;
//释放前次的查询结果
if ( $this->queryID ) {    $this->free();    }
N('db_query',1);
// 记录开始执行时间
G('queryStartTime');
$this->queryID = mysql_query($str, $this->_linkID);
$this->debug();
if ( false === $this->queryID ) {
$this->error();
return false;
} else {
$this->numRows = mysql_num_rows($this->queryID);
return $this->getAll();
}
}

注意看标蓝的地方。关于stripos()函数我不多说。这里直接将数据连接给关闭了,那么到了if ( !$this->_linkID ) return false;这行代码时,果断的会return false!!!因此症结就在此。所以注释掉就好了。至于为什么?

看绿色代码这两个方法是php本身的方法,ThinkPHP只实现了对他们的封装。继续跟代码:$this->getAll();

走到了:

   /**
* 获得所有的查询数据
* @access private
* @return array
*/
private function getAll() {
//返回数据集
$result = array();
if($this->numRows >0) {
while($row = mysql_fetch_assoc($this->queryID)){
$result[]   =   $row;
}
mysql_data_seek($this->queryID,0);
}
return $result;
}

有没有一目了然呢?这一片紫色的部分不正是一个循环么?

那么跟我图中所注释掉的代码不正是使用的同样的php基础方法么?

因此。将query方法中关于存储过程的那段屏蔽掉即可实现。

好吧。这个。我还是鲁莽了。各位注意:这里仅仅只是对于查询调用存储过程返回结果集的解决方案,至于执行存储过程要求返回影响数据库行数,从代码的分析上,不存在任何问题。

最后,我将自己写的存储过奉上希望能够帮助大家:

1:

CREATE DEFINER=`root`@`localhost` PROCEDURE `orgTree`()
BEGIN
declare tempId int;
declare tempName varchar(45);
declare tempFatherId int;
-- 创建临时表空,用来存放数据。
CREATE  TEMPORARY TABLE IF NOT EXISTS orgTreeTemp( id int not null primary key AUTO_INCREMENT , deptId int,name varchar(45) not null, fatherId int not null) ;
delete from orgTreeTemp where id> 0 ;
select id ,name,fatherId into tempId,tempname,tempFatherId from department where level= (select min(level) from department);
insert into orgTreeTemp (deptId,name,fatherId) values(tempId,tempname,tempFatherId);
call getChildTree(tempId);
select o.deptId as id,o.name as name ,d.description ,o.fatherId as fatherId ,d.level from orgTreeTemp o left join department d on o.deptId = d.id;
drop table orgTreeTemp;
END

2:

CREATE DEFINER=`root`@`localhost` PROCEDURE `getChildTree`(in root int)
BEGIN
declare tempId int;
declare tempName varchar(45);
declare tempFatherId int;
declare isRecordNotFound int default 0;
declare getC cursor  for select id,name,fatherId from department where fatherId = root;
declare continue handler for not found set isRecordNotFound = 1;
SET @@max_sp_recursion_depth = 255;

open getC;
fetch getC into tempId, tempName,tempFatherId;
while(isRecordNotFound != 1) do
insert into orgTreeTemp(deptId,name,fatherId) values(tempId,tempName,tempFatherId);
call getChildTree(tempId);
fetch getC into tempId, tempName,tempFatherId;
end while;
close getC;
END

点赞

发表回复

电子邮件地址不会被公开。必填项已用 * 标注