【原创】使用 mysql_use_result 仍是使用 mysql_store_result?


本文整理了关于“使用 mysql_use_result 仍是 mysql_store_result”的相关内容。

下面是网上找到的网友说法:
===============

博文一
      在使用 mysql_query() 进行一次查询后,通常要用这两个函数之一来把结果存到一个 MYSQL_RES * 变量中。
      二者的主要区别是,mysql_use_result() 的结果必须“一次性用完”,也就是说用它获得一个 result 后,必须反复用 mysql_fetch_row() 读取其结果直至该函数返回 null 为止,不然若是你再次进行 mysql 查询,会获得 “Commands out of sync; you can't run this command now” 的错误。而 mysql_store_result() 获得 result 是存下来的,你无需把所有行结果读完,就能够进行另外的查询。好比你进行一个查询,获得一系列记录,再根据这些结果,用一个循环再进行数据库查询,就只能用 mysql_store_result() 。


博文二
       对于成功检索了数据的每一个查询(SELECT、SHOW、DESCRIBE、EXPLAIN、CHECK TABLE 等),必须调用 mysql_store_result() 或 mysql_use_result() 。对于其余查询,不须要调用 mysql_store_result() 或 mysql_use_result() ,可是若是在任何状况下均调用了 mysql_store_result() ,它也不会致使任何伤害或性能下降。经过检查 mysql_store_result() 是否返回 0(NULL) ,可检测查询是否没有结果集(之后会更多)。
      若是但愿了解查询是否应返回结果集,可以使用 mysql_field_count() 进行检查。mysql_store_result() 将查询的所有结果读取到客户端,分配 1 个 MYSQL_RES 结构,并将结果置于该结构中。
      若是查询未返回结果集,mysql_store_result() 将返回 NULL 指针(例如,若是查询是 INSERT 语句)。
      若是读取结果集失败,mysql_store_result() 也会返回 NULL 指针。经过检查 mysql_error() 是否返回非空字符串,mysql_errno() 是否返回非 0 值,或 mysql_field_count() 是否返回 0 ,能够检查是否出现了错误。若是未返回行,将返回空的结果集。(空结果集设置不一样于做为返回值的空指针)。一旦调用了 mysql_store_result() 并得到了不是 NULL 指针的结果,可调用 mysql_num_rows() 来找出结果集中的行数。
      能够调用 mysql_fetch_row() 来获取结果集中的行,或调用 mysql_row_seek() 和 mysql_row_tell() 来获取或设置结果集中的当前行位置。一旦完成了对结果集的操做,必须调用 mysql_free_result() 。

返回值
具备多个结果的 MYSQL_RES 结果集合。若是出现错误,返回 NULL 。

错误
若是成功,mysql_store_result() 将复位 mysql_error() 和 mysql_errno() 。
· CR_COMMANDS_OUT_OF_SYNC
以不恰当的顺序执行了命令。
· CR_OUT_OF_MEMORY
内存溢出。
· CR_SERVER_GONE_ERROR
MySQL服务器不可用。
· CR_SERVER_LOST
在查询过程当中,与服务器的链接丢失。
· CR_UNKNOWN_ERROR
出现未知错误。


博文三
       当调用时,mysql_store_result() 当即检索全部的行,而 mysql_use_result() 启动查询,但实际上并未获取任何行,mysql_store_result() 假设随后会调用 mysql_fetch_row() 检索记录。这些行检索的不一样方法引发二者在其余方面的不一样。本节加以比较,以便了解如何选择最适合应用程序的方法。
      当 mysql_store_result() 从服务器上检索结果集时,就提取了行,并为之分配内存,存储到客户机中,随后调用 mysql_fetch_row() 就不再会返回错误,由于它仅仅是把行脱离了已经保留结果集的数据结构。mysql_fetch_row() 返回 NULL 始终表示已经到达结果集的末端。相反,mysql_use_result() 自己不检索任何行,而只是启动一个逐行的检索,就是说必须对每行调用 mysql_fetch_row() 来本身完成。既然如此,虽然正常状况下,mysql_fetch_row() 返回 NULL 仍然表示此时已到达结果集的末端,但也可能表示在与服务器通讯时发生错误。可经过调用 mysql_errno() 和 mysql_error() 将二者区分开来。
       与 mysql_use_result() 相比,mysql_store_result() 有着较高的内存和处理需求,由于是在客户机上维护整个结果集,因此内存分配和建立数据结构的耗费是很是巨大的,要冒着溢出内存的危险来检索大型结果集,若是想一次检索多个行,可用 mysql_use_result()。mysql_use_result() 有着较低的内存需求,由于只需给每次处理的单行分配足够的空间。这样速度就较快,由于没必要为结果集创建复杂的数据结构。另外一方面,mysql_use_result() 把较大的负载加到了服务器上,它必须保留结果集中的行,直到客户机看起来适合检索全部的行。


博文四
       客户端处理结果集的方式有两种。一种方式是,经过调用 mysql_store_result(),一次性地检索整个结果集。该函数能从服务器得到查询返回的全部行,并将它们保存在客户端。第二种方式是针对客户端的,经过调用 mysql_use_result(),对“按行”结果集检索进行初始化处理。该函数能初始化检索结果,但不能从服务器得到任何实际行。
       在这两种状况下,均能经过调用 mysql_fetch_row() 访问行。经过 mysql_store_result(),mysql_fetch_row() 可以访问之前从服务器得到的行。经过mysql_use_result(),mysql_fetch_row() 可以实际地检索来自服务器的行。经过调用 mysql_fetch_lengths(),能得到关于各行中数据大小的信息。
       完成结果集操做后,请调用 mysql_free_result() 释放结果集使用的内存。
       这两种检索机制是互补的。客户端程序应选择最能知足其要求的方法。实际上,客户端最常使用的是 mysql_store_result() 。
       mysql_store_result() 的 1 个优势在于,因为将行所有提取到了客户端上,你不只能连续访问行,还能使用 mysql_data_seek() 或 mysql_row_seek()在结果集中向前或向后移动,以更改结果集内当前行的位置。经过调用 mysql_num_rows(),还能发现有多少行。另外一方面,对于大的结果集,mysql_store_result() 所需的内存可能会很大,你极可能遇到内存溢出情况。
       mysql_use_result() 的 1 个优势在于,客户端所需的用于结果集的内存较少,缘由在于,一次它仅维护一行(因为分配开销较低,mysql_use_result()能更快)。它的缺点在于,你必须快速处理每一行以免妨碍服务器,你不能随机访问结果集中的行(只能连续访问行),你不知道结果集中有多少行,直至所有检索了它们为止。不只如此,即便在检索过程当中你断定已找到所寻找的信息,也必须检索全部的行。


下面是官网说法:
===============

【22.8.15. Common Questions and Problems When Using the C API
【22.8.15.1. Why mysql_store_result() Sometimes Returns NULL After mysql_query() Returns Success】

成功调用 mysql_query() 后,调用 mysql_store_result() 却返回 NULL 是可能的。当发生该状况时,有多是由于下面状况的出现:
  • 出现 malloc() 失败的状况(例如,得到的结果集太大)。
  • 调用 mysql_store_result() 时,当前使用的 TCP 链接已意外断开,致使没法读取数据。
  • 调用 mysql_store_result() 后确实应该无数据返回(例如调用的是 INSERT、UPDATE 或 DELETE)。
       不管什么时候,你均可以经过调用 mysql_field_count() 来肯定前一条执行的语句是否产生了非空结果集。若是 mysql_field_count() 返回的是 0 ,那么结果集必然是空的(返回 NULL ),最后调用的查询一定为不会返回结果集的语句(例如 INSERT 或 DELETE )。若是 mysql_field_count() 返回非 0 值,那么最后一条查询语句应该返回非空结果集。 (若是此时你得到了空结果集)你能够经过调用 mysql_error() 或者 mysql_errno() 来查看错误信息。

【22.8.15.2. What Results You Can Get from a Query】
在调用查询命令后除了能够得到结果集外,还能够经过以下命令得到更多信息:
  • 调用 mysql_affected_rows() 会返回执行最后一条查询语句(如 INSERT、UPDATE 或 DELETE )后所影响的 row 的数量。
  • 快速重建表,可使用 TRUNCATE TABLE 。
  • 调用 mysql_num_rows() 会返回结果集中的 row 的数量。若是是使用 mysql_store_result() 来获取结果集,那么只要在 mysql_store_result() 返回后,马上就能够调用 mysql_num_rows() 来获取 row 的数量。若是是使用 mysql_use_result() 来获取结果集,那么必须在使用 mysql_fetch_row() 获取到结果集的所有 row 后,才能调用 mysql_num_rows() 来后去 row 的数量。
  • 调用 mysql_insert_id() 会返回向具备 AUTO_INCREMENT 索引的表插入 row 时所产生的最后一个 ID 。
  • 有一些查询(如 LOAD DATA INFILE ..., INSERT INTO ... SELECT ..., UPDATE)会返回额外的信息。其结果能够经过 mysql_info() 来获取。

【Appendix C. Errors, Error Codes, and Common Problems】
【C.5.2. Common Errors When Using MySQL Programs】
【C.5.2.14. Commands out of sync】
       若是你遇到了 “Commands out of sync” 错误,你的客户端程序将不可以在当下成功执行(有结果集返回的)新的查询命令,由于你以错误的执行序列进行了调用。
       例如,当你在调用 mysql_use_result() 后,在未调用 mysql_free_result() 以前,又执行了一个新的查询操做就会出现上述问题。还有一种状况是,当你连续调用可以得到结果集的查询命令,却在其连续调用中间未调用 mysql_use_result() 或 mysql_store_result() 来获取结果集的状况。
=============

有了上面的研究,已经很清楚二者以前的差异了:
  • 分别会消耗客户端或服务器的内存;
  • 执行后续操做的约束不一样。
       决定选择的关键仍是要看,客户端程序是否关心结果集的内容。就 modb 而言,不太关心具体内容,只要知道成功仍是失败就能够了。因此我只须要肯定调用 mysql_query() 是否返回成功就能够了。

=============  

公司 dbi 库中对  mysql_use_result() 的使用:
EOpCode CMySqlHandlerImp::GoOnProcRes(BOOL32 bIsClear/* = false */)
{
    // 只要结果集不为 NULL 就释放掉
    if(NULL != m_pRes)
	{
		mysql_free_result(m_pRes);	 // clear preceding query result
		m_pRes = NULL;
	}
    ...
	// 在 bIsClear 为 True 的状况下,此处至关于将前次请求的所有结果集清除掉
	while(TRUE)
	{
        ...
		// 读取下一个查询结果
		nRet = mysql_next_result(m_pMySql);
        ...
		// 启动一个逐行的检索
		m_pRes = mysql_use_result(m_pMySql);    // 这里使用的 mysql_use_result
        ...
		if(!bIsClear)
		{
		    // 绑定结果集到自定义的保存结果集的容器中
			m_pcMySqlRsImp->BindRs(m_pMySql, m_pRes, m_pcCbFunc, m_pcContext);
			return EOpCode_FindRs;
		}
		mysql_free_result(m_pRes);
		m_pRes = NULL;
	}
}


BOOL32 CMySqlRsImp::BindRs(MYSQL *pMySql, MYSQL_RES *pRes, DBCbFunc pcCbFunc, void *pcContext)
{
	m_pMySql = pMySql;
	m_pRes = pRes;
	m_pcCbFunc = pcCbFunc;
	m_pcContext = pcContext;
	m_wColNum = (u16)mysql_field_count(pMySql);
	m_pField = mysql_fetch_fields(m_pRes);    // 这和 mysql_use_result 一块儿使用能够么
	m_bEnd = FALSE;   //产生记录集,修改结束标志位
	return TRUE;
}


BOOL32 CMySqlHandlerImp::ExecSql(IN LPCSTR szsql, OUT CDBRsImp *pcRecordSet, u16* pwErrId/* = NULL*/)
{
    ...
	// 清除前次请求的所有结果集
	GoOnProcRes(TRUE);
	
	// 执行新的查询操做
	s32 nRet = mysql_real_query(m_pMySql, szsql, strlen(szsql)+1);

	// 将外部指定的 buffer 进行绑定
	m_pcMySqlRsImp = (CMySqlRsImp *)pcRecordSet;
	
	// 获取这次请求的结果集
	if(GoOnProcRes() == EOpCode_FindRs)
    {
        u32 dwEndTime = OspTickGet();
		if (NULL != pwErrId)
		{
			*pwErrId = DB_EXEC_ERRID_SUCC;
		}
        return TRUE;
    }

	return FALSE;
}
相关文章
相关标签/搜索