1

对不起,我的英语很抱歉,如果这条信息不正确,我很抱歉——这是我的第一个问题。

在程序调用之后,当我试图解决一个与 mysql 断开连接的有趣问题时,我已经失去了 2 个晚上。这会更有趣,当我要说的时候,这个问题只出在过程中的 SELECT 查询上。

所以,我的例子。我有 2 个课程和程序:

1) DBCONN - 用于连接和处理查询。

class DBCONN
{
    private $mysqlC = null;

    public function __construct()
    {
        $this->CreateConnection();
    }

    public function __destruct() 
    {
        //$this->mysqlC->close();
    }

    private function CreateConnection()
    {
        $mC = new mysqli("localhost", "root", "root", "root");

        if ($mC->connect_error)
            die('Bye. '.$mC->connect_errno."-".$mC->connect_error);
        else 
            $mC->set_charset("utf8");

        $this->mysqlC = $mC;
    }

    private function CloseConnection()
    {
        $this->mysqlC->close();
    }

    private function _error()
    {
        die('Bye. '.$this->mysqlC->connect_errno."-".$this->mysqlC->connect_error);
    }

    public function SetData($call, $types = null, $params = null)
    {
        //$this->CreateConnection();

        $stmt = $this->mysqlC->stmt_init();

        if ($stmt->prepare($call) === FALSE) 
            $this->_error();

        if ($params && call_user_func_array(array($stmt, "bind_param"),     array_merge(array($types), $params)) === FALSE)
            $this->_error();
        if ($stmt->execute() === FALSE) 
            $this->_error();

        $insid = $stmt->insert_id;
        $affrows = $stmt->affected_rows;

        $stmt->close();

        //$this->CloseConnection();

        return array($insid, $affrows);
    }

    public function GetData($call, $types = null, $params = null)
    {
        //$this->CreateConnection();
        //#LOOK HERE BEGIN
        print 'status = '.$this->mysqlC->ping();
        //#LOOK HERE END
        //print $call;

        $stmt = $this->mysqlC->stmt_init();

        if ($stmt->prepare($call) === FALSE) 
            $this->_error();

        if ($params && call_user_func_array(array($stmt, "bind_param"), array_merge(array($types), $params)) === FALSE)
            $this->_error();

        if ($stmt->execute() === FALSE) 
            $this->_error();
        if ($stmt->store_result() === FALSE) 
            $this->_error();

        $meta = $stmt->result_metadata();

        while ($field = $meta->fetch_field())
             $var[] = &$row[$field->name];

        call_user_func_array(array($stmt, 'bind_result'), $var);

        $arr = null;

        while ($stmt->fetch())
        {
            foreach($row as $key => $val)
                $c[$key] = $val;

            $arr[] = $c;
        }

        $stmt->close();

        //$this->CloseConnection();

        return $arr;        
    }

}

2) BASEACTIONS - 创建 DBCONN 对象并向其发送文本命令。

class BASEACTIONS
{
    private $conn = null;
    public function __construct() {
        $this->conn = new DBCONN();
    }

    private function CheckPassword($email = '', $pass = '')
    {
        //#LOOK HERE BEGIN
        $arr = $this->conn->GetData("CALL Login_Actions(-1, '$email', '', '$pass', '');"); 
        $arr = $this->conn->GetData("CALL Login_Actions(-1, '$email', '', '$pass', '');");
        //#LOOK HERE END

        return ($arr[0]['isTrue']==1 ? true : false);
    }

    private function UpdateSession($email)
    {
        if (!session_regenerate_id()) return false;
        $session = session_id();

        $this->conn->SetData(
            "CALL Login_Session(2, ?, ?)",
            "ss", 
            array(&$email, &$session)
        );

        return true;
    }


    public function LoginUser($email = '', $pass = '')
    {
        if (!$this->UpdateSession($email)) return false;
        if (!$this->CheckPassword($email, $pass)) return false;

        return true;
    }
}

3) 存储过程

CREATE DEFINER=`root`@`localhost` PROCEDURE `Login_Actions`(
_action INT, 
_vcEmail varchar(50),
_vcNickname varchar(20),
_vcPassword varchar(255),
_vcPasssalt varchar(10)
)
BEGIN

case _action
    when -1 then
        select md5(concat(md5(_vcPassword), vcPasssalt)) = vcPassword 'isTrue' from Login where vcEmail=_vcEmail;
    when 0 then
        select iId, vcEmail, vcNickname from Login;
    when 1 then
        insert into Login(vcEmail, vcNickname, dtDateAdd, vcPassword, vcPasssalt) values(_vcEmail, _vcNickname, UTC_TIMESTAMP(), md5(concat(md5(_vcPassword), _vcPasssalt)), _vcPasssalt);
end case;

END

好吧...我在这些代码中为您标记了 2 个块,例如“//#LOOK HERE” - 请在之前找到它。

如果你将实现下一个代码......

$BASE = new BASEACTIONS();
$BASE->LoginUser("mail@mail.com", "mypassword");

...页面将返回给您

status = 1
status = Bye. 0-

但是,如果您将更改“CALL Login_Actions(-1, '$email', '', '$pass', '');" 在查询使用这些参数“select md5(concat(md5($pass), vcPasssalt)) = vcPassword 'isTrue' from Login where vcEmail=$email;”的哪种情况下,你会得到 OK 的结果。

status = 1
status = 1

我无法理解-为什么每次在使用 SELECT 进行 PROCEDURE 之后都会关闭 mysql 连接?PROCERUDE 中的 INSERT 没有问题。拜托,帮帮我——我在扯我的头发。

UPD:“if ($stmt->prepare($call) === FALSE) $this->_error();”中发生错误 GetData 方法。第一次实施还可以,其他都不好。

4

2 回答 2

0

正如您可能已经猜到的那样,这个问题与“mysql”连接无关,这很好。之后,我安装了你的代码,我得到了类似的错误。

我这里有你所有的代码,它可以工作。但是,我在其中放了很多调试代码,目前还很不整洁。

您遇到的主要问题是“DBConn”类。实际的错误是 'store_result' 有效返回 false 并且您将 false 视为错误。我还修改了代码以符合编码标准,例如所有“控制流语句”如“if”必须使用大括号。我稍微重组了代码以使其更易于阅读。

我没有以任何方式改变整体逻辑。

它现在更清楚地显示错误

它在 Windows XP 上的 PHP 5.3.18 和 MySQL 5.5.16 上工作,但没有经过很好的测试。以后有什么问题请留言。我会把它们整理出来。

DBConn 类:

<?php // 24321955/error-after-calling-mysql-stored-procedures

class DBConn
{
    private $mysqlC = null;

    public function __construct()
    {
        $this->CreateConnection();
    }

    private function CreateConnection()
    {
        $mC = new mysqli("localhost", "test", "test", "testmysql");

        if ($mC->connect_error)
            die('Bye. '.$mC->connect_errno."-".$mC->connect_error);
        else
            $mC->set_charset("utf8");

        $this->mysqlC = $mC;
    }

    private function CloseConnection()
    {
        $this->mysqlC->close();
    }

    private function _error($msg = '', $errno = 0, $error = '')
    {
        die("Bye. {$msg} ".
                   ($errno != 0 ? "errno: {$errno} - {$error}"
                                : "errno: {$this->mysqlC->errno} - {$this->mysqlC->error}"));
    }

    public function SetData($call, $types = null, $params = null)
    {
        //$this->CreateConnection();

        $stmt = $this->mysqlC->stmt_init();

        if ($stmt->prepare($call) === false) {
            $this->_error(__FILE__.__LINE__, $stmt->errno, $stmt->error);
        }

        if ($params) {
            $result = call_user_func_array(array($stmt, "bind_param"),
                                                  array_merge(array($types), $params));
            if ($result === false) {
                $this->_error(__FILE__.__LINE__, $stmt->errno, $stmt->error);
            }
        }

        if ($stmt->execute() === false) {
            $this->_error(__FILE__.__LINE__, $stmt->errno, $stmt->error);
        }

        $insid = $stmt->insert_id;
        $affrows = $stmt->affected_rows;

        $stmt->close();

        //$this->CloseConnection();

        return array($insid, $affrows);
    }

    public function GetData($call, $types = null, $params = null)
    {
        $stmt = $this->mysqlC->stmt_init();

        if ($stmt->prepare($call) === false) {
            $this->_error(__FILE__.__LINE__, $stmt->errno, $stmt->error);
        }

        if ($params) {
            $result = call_user_func_array(array($stmt, "bind_param"),
                                           array_merge(array($types), $params));
            if ($result === false) {
                $this->_error(__FILE__.__LINE__, $stmt->errno, $stmt->error);
            }
        }

        if ($stmt->execute() === false) {
            $this->_error(__FILE__.__LINE__, $stmt->errno, $stmt->error);
        }

        $result = $stmt->store_result();
        if ( $result === false && !empty($stmt->error) ) { // sometimes no result is ok!
            $this->_error(__FILE__.__LINE__, $stmt->errno, $stmt->error);
        }

        $meta = $stmt->result_metadata();

        while ($field = $meta->fetch_field()) {
             $var[] = &$row[$field->name];
        }

        call_user_func_array(array($stmt, 'bind_result'), $var);

        $arr = null;

        while ($stmt->fetch()) {
            foreach($row as $key => $val)
                $c[$key] = $val;

            $arr[] = $c;
        }

        $stmt->close();

        //$this->CloseConnection();

        return $arr;
    }
}
于 2014-06-20T17:31:03.307 回答
0

我找到了一些解决方案。它并不漂亮,但它可以工作并有助于解决在 1 个连接中调用多个过程的问题。

我需要在我的 GetData 方法中添加这一行。

$stmt->close();
while(mysqli_more_results($this->mysqlC))  //<<<<---- this line
    mysqli_next_result($this->mysqlC); //<<<<---- this line

return $arr;

所以,最后一课是:

class DBConn
{
private $mysqlC = null;

public function __construct()
{
    $mC = new mysqli("localhost", "user", "password", "database");

    if ($mC->connect_error)
        $this->Error("Bye. ", $mC->connect_errno, $mC->connect_error);
    else
        $mC->set_charset("utf8");

    $this->mysqlC = $mC;
}

public function __destruct()
{
    $this->mysqlC->close();
}

private function IsConnected()
{
    return $this->mysqlC->ping();
}

private function Error($msg = '', $errno = 0, $error = '')
{
    die("Bye. {$msg} ".
               ($errno != 0 ? "errno: {$errno} - {$error}"
                            : "errno: {$this->mysqlC->errno} - {$this->mysqlC->error}"));
}

public function SetData($call, $types = null, $params = null)
{
    $stmt = $this->mysqlC->stmt_init();

    if ($stmt->prepare($call) === false) {
        $this->Error("", $stmt->errno, $stmt->error);
    }

    if ($params) {
        $result = call_user_func_array(array($stmt, "bind_param"),
                                              array_merge(array($types), $params));
        if ($result === false) {
            $this->Error("", $stmt->errno, $stmt->error);
        }
    }

    if ($stmt->execute() === false) {
        $this->Error("", $stmt->errno, $stmt->error);
    }

    $insid = $stmt->insert_id;
    $affrows = $stmt->affected_rows;

    $stmt->close();

    return array($insid, $affrows);
}

public function GetData($call, $types = null, $params = null)
{
    $stmt = $this->mysqlC->stmt_init();

    if ($stmt->prepare($call) === false) {
        $this->Error("", $stmt->errno, $stmt->error);
    }

    if ($params) {
        $result = call_user_func_array(array($stmt, "bind_param"),
                                       array_merge(array($types), $params));
        if ($result === false) {
            $this->Error("", $stmt->errno, $stmt->error);
        }
    }

    if ($stmt->execute() === false) {
        $this->Error("", $stmt->errno, $stmt->error);
    }

    $result = $stmt->store_result();
    if ( $result === false && !empty($stmt->error) ) { // failing!!! and throw away result
        $this->Error("", $stmt->errno, $stmt->error);
    }

    $meta = $stmt->result_metadata();

    while ($field = $meta->fetch_field()) {
         $var[] = &$row[$field->name];
    }

    call_user_func_array(array($stmt, 'bind_result'), $var);

    $arr = null;

    while ($stmt->fetch()) {
        foreach($row as $key => $val)
            $c[$key] = $val;

        $arr[] = $c;
    }

    $stmt->close();
    while(mysqli_more_results($this->mysqlC))  //<<<<---- this line
        mysqli_next_result($this->mysqlC); //<<<<---- this line

    return $arr;
}
}

谢谢大家,极客!

于 2014-06-20T20:02:28.540 回答