• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • mysqli::store_result()

    (PHP 5, PHP 7)

    转移上一次查询返回的结果集

    说明

    面向对象风格
    mysqli::store_result([int $option]): mysqli_result
    过程化风格
    mysqli_store_result(mysqli$link[,int $option]): mysqli_result

    迁移$link参数所指定的连接上的上一次查询返回的结果集,迁移之后的结果集可以在mysqli_data_seek()函数中使用。

    参数

    $link

    仅以过程化样式:由mysqli_connect()或mysqli_init()返回的链接标识。

    $option

    指定的选项,可以是下列中的某一值:

    Valid options
    NameDescription
    MYSQLI_STORE_RESULT_COPY_DATA将结果集从 mysqlnd 的内部缓冲区复制到 PHP 变量中。默认情况下,mysqlnd 采取一种引用策略尽量避免在内容中复制多份同样的结果集。例如,对于一个包含了很多行的结果集,每个行中的内容又不是很大,那么复制结果集的过程会导致内存使用率下降,因为用来保存结果集数据的 PHP 变量可能提前被释放掉。(此选项仅在使用 mysqlnd 驱动且 PHP 5.6.0 之后可用)。

    返回值

    成功则返回一个缓冲的结果集对象,失败则返回FALSE

    Note:

    如果上一查询并不产生结果集(例如,执行了一个 INSERT 语句),那么mysqli_store_result()会返回FALSE。如果读取结果集失败了,也会返回FALSE。如何区分是上面哪种情况导致此函数的调用返回了FALSE?你可以通过下面的方法来检测:mysqli_error()返回了非空的字符串,mysqli_errno()返回了非零值,或者mysqli_field_count()返回了非零值,都表示发生错误了。还有一种可能的情况会导致此函数的调用返回FALSE:上一次查询mysqli_query()本身是成功的,但是由于返回的结果集太大,无法为其分配足够的内存来进行结果集转移。如果mysqli_field_count()函数返回了一个非零值,那么表示 SQL 语句产生了一个非空的结果集。

    注释

    Note:

    执行查询之后,使用mysqli_free_result()函数来释放结果集所占用的内存,是一个很有用的实战经验。尤其是当使用mysqli_store_result()函数来转移数量较大的结果集的时候,释放结果集内存的操作尤为重要。

    范例

    See mysqli_multi_query().

    参见

    • mysqli_real_query() 执行一个mysql查询
    • mysqli_use_result() Initiate a result set retrieval
    After reading through original notes and example above as well as wading through the documentation, I finally got a loop to work with two stored procedures.
    Using the results of the first one as a parameter for the second one. Easier to do this way than a huge modified sequence of Inner Join queries.
    Hope this helps others...
    <?php
    // Connect to server and database
    $mysqli    = new mysqli("$dbServer", "$dbUser", "$dbPass", "$dbName");
    // Open First Stored Procedure using MYSQLI_STORE_RESULT to retain for looping
    $resultPicks = $mysqli->query("CALL $proc ($searchDate, $maxRSI, $incRSI, $minMACD, $minVol, $minTrades, $minClose, $maxClose)", MYSQLI_STORE_RESULT);
    // process one row at a time from first SP
    while($picksRow = $resultPicks->fetch_array(MYSQLI_ASSOC)) {
      // Get Parameter for next SP
      $symbol   = $picksRow['Symbol'];
      // Free stored results
      clearStoredResults($mysqli);
      // Execute second SP using value from first as a parameter (MYSQLI_USE_RESULT and free result right away)
      $resultData  = $mysqli->query("CALL prcGetLastMACDDatesBelowZero('$symbol', $searchDate)", MYSQLI_USE_RESULT);
      $dataRow  = $resultData->fetch_array(MYSQLI_ASSOC);
      // Dump result from both related queries
      echo "<p>$symbol ... Num Dates: " . $dataRow['NumDates'];
      // Free results from second SP
      $resultData->free();
    }
    // Free results from first SP
    $resultPicks->free();
    // close connections
    $mysqli->close();
    #------------------------------------------
    function clearStoredResults($mysqli_link){
    #------------------------------------------
      while($mysqli_link->next_result()){
       if($l_result = $mysqli_link->store_result()){
           $l_result->free();
       }
      }
    }
    ?>
    
    Code to handling errors:
    if ($mysqli->multi_query($query)) {
      $result = $mysqli->store_result();
      if ($mysqli->errno == 0) {
      
        /* First result set or FALSE (if the query didn't return a result set) is stored in $result */
        while ($mysqli->more_results()) {
          if ($mysqli->next_result()) {
            $result = $mysqli->store_result();
            if ($mysqli->errno == 0) {
              /* The result set or FALSE (see above) is stored in $result */
            }
            else {
              /* Result set read error */
              break;
            }
          }
          else {
            /* Error in the query */
          }
        }
      }
      else {
        /* First result set read error */
      }
    }
    else {
      /* Error in the first query */
    }
    Beware when using stored procedures:
    If you connect to the database and then call dbproc A followed by a call to db proc B and then close the connection to the db, the second procedure call will not work.
    It looks like there is a bug in MYSQL or mysqli that returns an extra recordset than you would expect. It then doesn't let you call another stored procedure until you finish processing all the recordsets from the first stored procedure call. 
    The solution is to simply loop through the additional recordsets between calls to db procs. Here is a function that I call between db proc calls:
    <?php
    #--------------------------------
    function ClearRecordsets($p_Result){
    #--------------------------------
      $p_Result->free();  
      while($this->Mysqli->next_result()){
       if($l_result = $this->Mysqli->store_result()){
           $l_result->free();
       }
      }
    }
    ?>
    
    There's a simpler way to clear out database stored procedure problems:
    class MySQLiQuery {
       protected $_resultSet;
       protected $databaseConnection;
    ....
      protected function free(){
        $this->_resultSet->free();
        $this->_resultSet=null;
      }
      protected function checkMoreResults(){
        if($this->databaseConnection->more_results()){
          return true;
        } else {
          return false;
        }
      }
      protected function clearResults(){
        if($this->checkMoreResults()){
          if($this->databaseConnection->next_result()){
            if($this->_resultSet=$this->databaseConnection->store_result()){
              $this->free();
            }
            $this->clearResults(); // <----------- recursive call is your friend
          }
        }
      }
    .......
    }
    It also seems, that executing a SET statement in multi_query() returns an extra recordset too, which one would not expect.