【原创】使用 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() 的使用: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

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;

}

时间: 2025-01-20 17:08:08

【原创】使用 mysql_use_result 还是使用 mysql_store_result?的相关文章

如何处理MYSQL查询

    6.6 处理查询    我们已经知道了如何开始和结束与服务器的会话,现在应该看看如何控制会话.本节介绍了如何与服务器通信以处理查询.执行的每个查询应包括以下几步:    1) 构造查询.查询的构造取决于查询的内容-特别要看是否含有二进制数据.    2) 通过将查询发送到服务器执行来发布查询.    3) 处理查询结果.这取决于发布查询的类型.例如, SELECT 语句返回数据行等待处理,INSERT 语句就不这样.构造查询的一个要素就是使用哪个函数将查询发送到服务器.较通用的发布查询例

各种MySQL客户环境变量程序概述

所有使用mysqlclient客户库与服务器通信的MySQL客户使用下列环境变量: 使用MYSQL_PWD是不安全的.见6.3 与MySQL服务器连接. "mysql"客户使用MYSQL_HISTFILE环境变量中命名的文件来保存命令行历史,历史文件的缺省值是"$HOME/.mysql_history",这里$HOME是HOME环境变量的值. 所有MySQL程序取许多不同的选项,然而,每个MySQL程序提供一个--help选项,你可以使用它得到程序不同选项的完整描述

Linux C语言操作MySQL

原文:Linux C语言操作MySQL 1.MySQL数据库简介 MySQL是一个开源码的小型关系数据库管理系统,体积小,速度快,总体成本低,开源.MySQL有以下特性: (1) 使用C和C++编写,并使用了多种编译器进行测试,保证源码的可移植性. (2) 支持多线程,利用CPU资源,支持多用户. (3) 可以处理拥有上千万条记录的大型数据库. (4)既可以作为一个单独的应用程序应用在客户端服务器网络环境中,也能够作为 一个库而嵌入到其他软件中去.   2. MySQL数据库的安装 安装MySQ

MySQL 相关的环境变量_Mysql

使用MYSQL_PWD是不安全的.见6.3 与MySQL服务器连接. "mysql"客户使用MYSQL_HISTFILE环境变量中命名的文件来保存命令行历史,历史文件的缺省值是"$HOME/.mysql_history",这里$HOME是HOME环境变量的值. 所有MySQL程序取许多不同的选项,然而,每个MySQL程序提供一个--help选项,你可以使用它得到程序不同选项的完整描述.例如,试一试mysql --help. 你能用一个选项文件覆盖所有的标准客户程序的

【原创】基于 MySQL Connector/C 实现客户端程序之 API 总结

[关于 mysql_query() ] 下面是官网对于 mysql_query() 的说明. ===  [22.8.7.52. mysql_query()]  ? 1 int mysql_query(MYSQL *mysql, const char *stmt_str) 功能:  执行由 stmt_str 指定的 NULL 结尾的 SQL 语句.通常情况下,由 stmt_str 指定的内容是单条 SQL 语句,且结尾没有分号 ";" 或者 "\g" .如果使能了多语

【原创】modb 功能设计之“支持部分MySQL客户端协议”-3

 在研究完 MySQL 官方文档上对 Connector/C 的说明后,终于可以 开工实践了,先搞个小 demo 出来运行看看.  开发环境:Windows XP SP3 v11 + VS2010 + MySQL Connector/C 6.1.2 测试代码: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include <stdio.h> #

The Hybrid Response(原创)

The Hybrid Response When requirements call for changed data to result in both type 1 and type 2 behavior, the solution is disarmingly simple: provide for both. This cannot be achieved with a single attribute, but it can be achieved by providing a pai

浅解逻辑分区LPAR与DLPAR(原创)

作为一个DBA,对操作系统及底层硬件的了解也许不是那么至关重要,但是越好的了解数据库所运行的环境就能越好的了解数据库.这里笔者简单介绍下LPAR与DLPAR 为什么服务器需要分区  近来,UNIX服务器的分区技术成为一个热点.分区技术在某些应用领域的确能带来实际的好处,但也不能一概而论.这些年分区技术的作用有被逐渐夸大的趋势,在有些时候还被描述成无所不能的技术,目前主流的分区技术可以分为物理分区.逻辑分区和动态逻辑分区. 分区的优点 服务器集中 服务器的集中管理和应用模式的集中可以减少总拥有成本

ETL概述(原创)

ETL概述ETL,Extraction- Transformation-Loading的缩写,即数据抽取(Extract).转换(Transform).装载(Load)的过程,它是构建数 据仓库的重要环节.ETL是将业务系统的数据经过抽取.清洗转换之后加载到数据仓库的过程,目的是将企业中的分散.零乱.标准不统一的数据整合到一起,为 企业的决策提供分析依据.ETL是BI项目重要的一个环节.通过ETL,我们可以基于源系统中的数据来生成数据仓库.ETL为我们搭建了OLTP系统和 OLAP系统之间的桥梁