zoukankan      html  css  js  c++  java
  • 使用 mysql_use_result 还是使用 mysql_store_result?

    From: http://my.oschina.net/moooofly/blog/186456

    本文整理了关于“使用 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;
    }
  • 相关阅读:
    Poj 2017 Speed Limit(水题)
    Poj 1316 Self Numbers(水题)
    Poj 1017 Packets(贪心策略)
    Poj 1017 Packets(贪心策略)
    Poj 2662,2909 Goldbach's Conjecture (素数判定)
    Poj 2662,2909 Goldbach's Conjecture (素数判定)
    poj 2388 Who's in the Middle(快速排序求中位数)
    poj 2388 Who's in the Middle(快速排序求中位数)
    poj 2000 Gold Coins(水题)
    poj 2000 Gold Coins(水题)
  • 原文地址:https://www.cnblogs.com/joeblackzqq/p/5594102.html
Copyright © 2011-2022 走看看