mysqli::store_result
mysqli_store_result
(PHP 5, PHP 7, PHP 8)
mysqli::store_result -- mysqli_store_result — 转移上一次查询返回的结果集
参数
-
mysql
-
仅以过程化样式:由mysqli_connect() 或 mysqli_init() 返回的 mysqli 对象。
-
option
-
指定的选项,可以是下列中的某一值:
Valid options Name Description MYSQLI_STORE_RESULT_COPY_DATA
将结果集从 mysqlnd 的内部缓冲区复制到 PHP 变量中。 默认情况下,mysqlnd 采取一种引用策略尽量避免在内容中复制多份同样的结果集。 例如,对于一个包含了很多行的结果集,每个行中的内容又不是很大,那么复制结果集的过程会导致内存使用率下降, 因为用来保存结果集数据的 PHP 变量可能提前被释放掉。 (此选项仅在使用 mysqlnd 驱动且 PHP 5.6.0 之后可用)。
返回值
成功则返回一个缓冲的结果集对象,失败则返回 false
。
注意:
如果上一查询并不产生结果集(例如,执行了一个 INSERT 语句), 那么 mysqli_store_result() 会返回
false
。 如果读取结果集失败了,也会返回false
。 如何区分是上面哪种情况导致此函数的调用返回了false
? 你可以通过下面的方法来检测: mysqli_error() 返回了非空的字符串, mysqli_errno() 返回了非零值, 或者 mysqli_field_count() 返回了非零值, 都表示发生错误了。 还有一种可能的情况会导致此函数的调用返回false
:上一次查询 mysqli_query() 本身是成功的, 但是由于返回的结果集太大,无法为其分配足够的内存来进行结果集转移。 如果 mysqli_field_count() 函数返回了一个非零值,那么表示 SQL 语句产生了一个非空的结果集。
注释
注意:
执行查询之后, 使用 mysqli_free_result() 函数来释放结果集所占用的内存, 是一个很有用的实战经验。 尤其是当使用 mysqli_store_result() 函数来转移数量较大的结果集的时候, 释放结果集内存的操作尤为重要。
范例
See mysqli_multi_query().
User Contributed Notes 5 notes
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 */
}
It also seems, that executing a SET statement in multi_query() returns an extra recordset too, which one would not expect.
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
}
}
}
.......
}