MySQL数据库技术(34)[MySQL防范]
本文“MySQL数据库技术(34)[MySQL防范]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:
6.6 处理查询
? ? 我们已经知道了若何开始和完毕与服务器的会话,目前应当看看若何掌握会话.本节介绍了若何与服务器通信以处理查询.履行的每个查询应包含以下几步:
? ? 1) 构造查询.查询的构造取决于查询的内容—分外要看能否含有二进制数据.
? ? 2) 通过将查询发送到服务器履行来公布查询.
? ? 3) 处理查询后果.这取决于公布查询的范例.比方, SELECT 语句返回数据行等候处理,INSERT 语句就不这样.构造查询的一个要素就是利用哪个函数将查询发送到服务器.较通用的公布查询例程是MySQL _ real _ query ( ).该例程给查询供应了一个计数串(字符串加上长度).必须理解查询串的长度,并将它们连同串本身一同传送给mysql_real_query() .因为查询是一个计数的字符串,
所以它的内容大概是任何东西,此中包含二进制数据大概空字节.查询不能是空终结串.另一个公布查询的函数, mysql _ query ( ),在查询字符串答应的内容上有更多的限制,但更简单利用一些.传送到mysql_query() 的查询应当是空终结串,这阐明查询内部不能含有空字节(查询里含有空字节会招致错误地中止,这比实际的查询内容要短).普通说来,假如查询包含肆意的二进制数据,便大概包含空字节,因此不要利用mysql _ query( ).另一方面,当处理空终结串时,利用熟习的尺度C 库字符串函数构造查询是很耗费资源的,比方strcpy ( )和sprintf( ).
? ? 构造查询的另一个要素就是能否要履行溢出字符的操作.假如在构造查询时利用含有二
进制数据大概其他复杂字符的值时,如引号、反斜线等,就需求利用这个操作.这些将在
? ? 6.8.2节"对查询中有疑问的数据举行编码"中谈论.
? ? 下面是处理查询的简单表面:
? ? mysql_query() 和mysql_real_query() 的查询成功城市返回零值,查询失利返回非零值.查询成功指服务器认为该查询有效并承受,并且可以履行,并非指有关该查询后果.比方,它不是指SELECT 查询所挑选的行,或DELETE 语句所删除的行.查抄查询的实际后果要包含其他的处理.
? ? 查询失利大概有多种缘由,有一些常见的缘由以下:
? ? ■ 含有语法错误.
? ? ■ 语义上是不法的—比方触及对表中不存在的列的查询.
? ? ■ 没有充足的权利拜候查询所引用的数据.
? ? 查询可以分成两大类:不返回后果的查询和返回后果的查询.INSERT、DELETE和UPDATE等语句属于"不返回后果"类的查询,即便对改正数据库的查询,它们也不返回任何行.可返回的唯一信息就是有关受作用的行数.SELECT 语句和SHOW 语句属于"返回后果"类的查询;公布这些语句的目的就是要返回某些信息.返回数据的查询所生成的行调集称为后果集,在MySQL 中表示为MYSQL_RES 数据范例,这是一个包含行的数据值及有关这些值的元数据(如列名和数据值的长度)的构造.空的后果集(就是包含零行的后果)要与"没有后果"区脱离.
? ? 6.6.1 处理不返回后果集的查询
? ? 处理不返回后果集的查询,用mysql_query() 或mysql_real_query() 公布查询.假如查询成功,可以通过调用mysql _ a ffected_rows() 找出有多少行需求插入、删除或改正.下面的样例阐明若何处理不返回后果集的查询:
? ? 请注意在打印时mysql _ a ffected_rows() 的后果是若何转换为unsigned long 范例的,这个函数返回一个my_ulonglong 范例的值,但在一些系统上无法直接打印这个范例的值(比方,笔者察看到它可在FreeBSD 下工作,但不能在Solaris 下工作).把值转换为unsigned long 范例并利用‘% l u’打印格局可以办理这个问题.一样也要考虑返回my_ulonglong 值的其他函数,如mysql_num_rows() 和mysql _ insert _ id ( ).假如想使客户机程序能跨系统地移植,就要服膺这一点.
? ? mysql _ rows _ affected() 返回查询所作用的行数,但是"受作用的行"的含义取决于查询的范例.关于INSERT、DELETE 和UPDATE,是指插入、删除大概更新的行数,也就是MySQL 实际改正的行数.假如行的内容与所要更新的内容相同,则MySQL 就不再更新行.这就是说固然大概挑选行来更新(通过UPDATE 语句的WHERE 子句),但实际上该行大概并未改变.
? ? 关于UPDATE,"受作用的行"的意义实际上是个争辩点,因为人们想把它当作"被匹配的行"—即挑选要更新的行数,即便更新操作实际上并未改变此中的值也是如此.假如利用程序需求这个信息, 则当与服务器衔接时可以用它来恳求以实现这个功效.将CLIENT_FOUND_ROWS 的flags 值传送给mysql _ real _ connect( ).也可以将CLIENT _ FOUND _ROWS 作为flags 参数传送给do _ connect ( );它将把值传送给mysql _ real _ connect( ).
? ? 6.6.2 处理返回后果集的查询
? ? 通过调用mysql_query() 和mysql_real_query() 公布查询之后,返回数据的查询今后果集情势举行.在MySQL 中实现它非常重要, SELECT 不是返回行的唯一语句, SHOW、DESCRIBE 和EXPLAIN 都需求返回行.对全部这些语句,都必须在公布查询后履行别的的处理行操作.
? ? 处理后果集包含下面几个步骤:
? ? ■ 通过调用mysql_store_result() 或mysql_use_result() 产生后果集.这些函数假如成功则返回MYSQL_RES 指针,失利则返回N U LL.稍后我们将查看mysql_store_result() 与mysql_use_result() 的差别,以及挑选此中一个而不选另一个时的情形.我们的样例使
用mysql _ store _ result( ),它能当即从服务器返回行,并将它们存储到客户机中.
? ? ■ 对后果集的每一行调用mysql _ fetch _ rows ( ).这个函数返回MYSQL_ROW 值,它是一个指向字符串数组的指针,字符串数组表示行中每列的值.要按照利用程序对行举行操作.可以只打印出列值,履行有关的统计计算,大概做些其他操作.当后果集合不再有行时, mysql_fetch_rows() 返回NULL.
? ? ■ 处理后果集时,调用mysql_free_result() 释放所利用的内存.假如忽视了这一点,则利用程序就会泄暴露内存(关于长期运行的利用程序,适本地办理后果集是极端重要的;不然,会注意到系统将由一些历程所代替,这些历程损耗着常常增长的系统资源量).
? ? 下面的样例表面介绍了若何处理返回后果集的查询:
? ? 我们通过调用函数process_result_set() 来处理每一行,这里有个诀窍,因为我们并没有定义这个函数,所以需求这样做.普通,后果的处理集函数是基于下面的循环:
? ? 从mysql_fetch_row() 返回的MYSQL_ROW 值是一个指向数值数组的指针,因此,拜候每个值就是拜候row[i],这里i 的范围是从0到该行的列数减1.这里有几个关于MYSQL_ROW 数据范例的要点需求注意:
? ? ■ MYSQL_ROW 是一个指针范例,因此,必须声明范例变量为MYSQL_ROW row,而不是MYSQL_ROW *row.
? ? ■ MYSQL_ROW 数组中的字符串是空终结的.但是,列大概含有二进制数据,这样,数据中便大概含有空字节,因此,不该该把值当作是空终结的.由列的长度可知列值有多长.
? ? ■ 全部数据范例的值都是作为字符串返回的,即便是数字型的也是如此.假如需求该值为数字型,就必须自己对该字符串举行转换.
? ? ■ 在MYSQL_ROW 数组中,NULL 指针代表N U L L,除非声明列为NOT NULL,不然应当常常查抄列值能否为NULL 指针.
? ? 利用程序可以操纵每行的内容做任何想做的事,为了举例阐明这一点,我们只打印由制表符离隔列值的行,为此还需求别的一个函数, mysql_num_fields() ,它来自于客户机库;这个函数奉告我们该行包含多少个值(列).
? ? 下面就是process_result_set() 的代码:
? ? process_result_set() 以制表符脱离的情势打印每一行(将NULL值显示为单词"NULL"),它跟在被检索的行计数的背面, 该计数通过调用mysql_num_rows() 来计算.像mysql _ affected_rows() 一样,mysql_num_rows() 返回my_ulonglong 值,因此,将值转换为
unsigned long 型,并用‘% l u’ 格局打印.
提取行的循环紧接在一个错误查验的背面,假如要用mysql_store_result() 成立后果集,
? ? mysql_fetch_row() 返回的N U L L值普通意味着"不再有行".但是,假如用mysql _ use _ result( )成立后果集,则mysql_fetch_row() 返回的NULL 值普通意味着"不再有行"大概发生了错误.无论怎样成立后果集,这个测试只答应process_result_set() 检测错误.
? ? process_result_set() 的这个版本是打印列值要求条件最低的办法,每种办法都有一定的缺陷,比方假定履行下面的查询:
? ? 我们可以通过供应一些信息如列标签,及通过使这些值垂直布列,而使输出后果漂亮一点.为此,我们需求标签和每列所需的最宽的值.这个信息是有效的,但不是列数据值的一部份,而是后果集的元数据的一部份(有关数据的数据).简单归纳了一下查询处理程序后,我们将在6 . 6 . 6节"利用后果集元数据"中给出较漂亮的显示格局.
? ? 打印二进制数据
? ? 对包含大概含有空字节的二进制数据的列值,利用‘ % s’printf() 格局标识符不能将它精确地打印; printf() 但愿一个空终结串,并且直到第一个空字节才打印列值.关于二进制数据,最好用列的长度,以便打印完好的值,如可以用fwrite() 或putc( ).
? ? 6.6.3 通用目标查询处理程序
? ? 前面介绍的处理查询样例利用了语句能否应当返回一些数据的知识来编写的.这是大概的,因为查询固定在代码内部:利用I N S E RT 语句时,它不返回后果,利用SHOW TABLES语句时,才返回后果.
? ? 但是,不大概始终知道查询用的是哪一种语句,比方,假如履行一个从键盘键入或根源于文件的查询,则它大概是任何的语句.不大概提早知道它能否会返回行.当然不想对查询做语法解析来决意它是哪类语句,总之,并不像看上去那样简单.只看第一个单词是不够的,因为查询也大概以注释语句开始,比方:
? ? /* comment * / SELECT
? ? 幸运的是没必要过早地知道查询范例就可以够精确地处理它.用MySQL C API 可编写一个能很好地处理任何范例语句的通用目标查询处理程序,无论它能否会返回后果.在编写查询处理程序的代码之前,让我们简述一下它是若何工作的:
? ? ■ 公布查询,假如失利,则完毕.
? ? ■ 假如查询成功,调用mysql_store_result() 从服务器检索行,并成立后果集.
? ? ■ 假如mysql_store_result() 失利,则查询不返回后果集,大概在检索这个后果集时发生错误.可以通过把衔接处理程序传送到mysql_field_count() 中,并检测其值来辨别这两种情形,以下:
? ? ■ 假如mysql_field_count() 非零,阐明有错误,因为查询应当返回后果集,但却没有.这种情形发生有多种缘由.比方:后果集大概太大,内存分配失利,大概在提取行时客户机和服务器之间发生网络中止.
? ? 这种历程略微有点复杂之处就在于, MySQL 3.22.24 之前的早期版本中不存在mysql _ field _ count( ),它们利用的是mysql _ num _ fields ( ).为编写MySQL 任何版本都能运行的程序,在调用mysql_field_count() 的文件中都包含下面的代码块:
? ? 这就将对mysql_field_count() 的一些调用看做是比MySQL 3.22.24 更早版本中的mysql_num_fields() 的调用.
? ? ■ 假如mysql_field_count() 返回0,就意味着查询不返回后果(这阐明查询是近似于INSERT、DELETE、或UPDATE 的语句).
? ? ■ 假如mysql_store_result() 成功,查询返回一个后果集,通过调用mysql_fetch_row() 来处理行,直到它返回NULL 为止.
? ? 下面的列表阐明了处理肆意查询的函数,给出了衔接处理程序和空终结查询字符串:
? ? 6.6.4 可挑选的查询处理办法
? ? process_query() 的这个版本有三个特点:
? ? ■ 用mysql_query() 公布查询.
? ? ■ 用mysql_store_query() 检索后果集.
? ? ■ 没有得到后果集时,用mysql_field_count() 把错误事件和不需求的后果集辨别开来.针对查询处理的这些特点,有以下三种办法:
? ? ■ 可以用计数查询字符串和mysql _ real _ query( ),而不利用空终结查询字符串和mysql _ query( ).
? ? ■ 可以通过调用mysql_use_result() 而不是调用mysql_store_result() 来成立后果集.
? ? ■ 可以调用mysql_error() 而不是调用mysql_field_count() 来肯定后果集是检索失利还是仅仅没有设置检索.
? ? 可用以上部份或全部办法替换process _ query( ).以下是一个process_real_query() 函数,它与process_query() 近似,但利用了全部三种办法:
? ? 6.6.5 mysql_store_result() 与mysql_use_result() 的对比
? ? 函数mysql_store_result() 与mysql_use_result() 近似,它们都有衔接处理程序参数,并返回后果集.但实际上二者间的辨别还是很大的.两个函数之间主要的辨别在于从服务器上检索后果集的行.当调用时, 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 _ use _ result( ):
? ? ■ 在用户的恳求下提早逐行举行的交互式客户机程序(没必要仅仅因为用户需求喝杯咖啡而让服务器等候发送下一行).
? ? ■ 在行检索之间做了很多处理的客户机程序.在全部这些情形下,客户机程序都不能很快检索后果集的全部行,它限制了服务器,并对其他客户机程序产生负面的影响,因为检索数据的表在查询历程中是读锁定的.要更新表的客户机或要插入行的任何客户机程序都被阻塞.
? ? 偏移由mysql_store_result() 惹起的额外内存需求对一次拜候整个后果集带来相当的好处.后果集合的全部行都是有效的,因此,可以肆意拜候: mysql _ data _ seek( )、mysql _ rowseek( )和mysql_row_tell() 函数答应以肆意次序拜候行.而mysql_use_result() 只能以mysql_fetch_row() 检索的次序拜候行.假如想要以肆意次序而不是从服务器返回的次序来处理行,就必须利用mysql _ store _ result( ).比方,假如答应用户往复地浏览查询所选的行,最好利用mysql _ store _ result( ).
? ? 利用mysql_store_result() 可以得到在利用mysql_use_result() 时是无效的某些范例的列信息.通过调用mysql_num_rows() 来得到后果集的行数,每列中的这些值的最大宽度值存储在MYSQL_FIELD 列信息构造的max_width 成员中.利用mysql _ use _ result( ),直到提取完好部的行,mysql_num_rows() 才会返回精确值,并且max_width 无效,因为只有在每行的数据都显示后才能计算.
? ? 由于mysql_use_result() 比mysql_store_result() 履行更少的操作,所以mysql _ use _ result( )就强加了一个mysql_store_result() 没有的需求:即客户机对后果集合的每一行都必须调用mysql _ fetch _ row( ),不然,后果集合剩余的记录就会成为下一个查询后果集合的一部份,并且发生"差别步"的错误.这种情形在利用mysql_store_result() 时不会发生,因为当函数返
回时,全部的行就已被获得.事实上,利用mysql_store_result() 就没必要再自己调用mysql _ fetch _ row( ).关于全部感爱好的事情就是能否得到一个非空的后果,而不是后果所包含的内容的查询来说,它是很有效的.比方,要知道表my_tbl 能否存在,可以履行下面的查询:
? ? SHOW TABLES LIKE "my_tb1"
? ? 假如在调用mysql_store_result() 之后,mysql_num_rows() 的值为非零,这个表就存在,就没必要再调用mysql_fetch_row() (当然仍需调用mysql _ free _ result( )).假如要供应最大的机动性,就给用户挑选利用任一后果集处理办法的选项.mysql 和mysqldump 是履行这个操作的两个程序,缺省时,利用mysql _ store _ result( ),但是假如指定--quick 选项,则利用mysql _ use _ result( ).
? ? 6.6.6 利用后果集元数据
? ? 后果集不但包含数据行的列值,并且还包含数据信息,这些信息成为元数据后果集,包含:
? ? ■ 后果集合的行数和列数,通过调用mysql_num_rows() 和mysql_num_fields() 实现.
? ? ■ 行中每列值的长度,通过调用mysql_fetch_lengths() 实现.
? ? ■ 有关每列的信息, 比方列名和范例、每列值的最大宽度和列根源的表等.
? ? MYSQL_FIELD 构造存储这些信息,通过调用mysql_fetch_fields() 来得到它.附录F具体地描写了MYSQL_FIELD 构造,并列出了供应拜候列信息的全部函数.元数据的有效性部份决意于后果集的处理办法,如在上节中提到的,假如要利用行计数大概列长度的最大值,就必须用mysql_store_result() 而不是mysql_use_result() 成立后果集.后果集元数据对肯定有关若何处理后果集非常有帮忙:
? ? ■ 列名和宽度信息对漂亮地生成带有列标题并垂直布列的格局化输出是非常有效的.
? ? ■ 利用列计数来肯定处理数据行的持续列值的循环所迭代的次数.假如要分配取决于后果集合已知的行数或列数的数据构造,便可以利用行或列计数.
? ? ■ 可以肯定列的数据范例.可以看出列能否是数字的,能否大概包含二进制数据等等.在前面的6.6.1节"处理返回后果集的查询"中,我们编写了从后果集的行中以制表符脱离的情势打印出后果的process_result_set() 程序.这对某些目的是很好的(比方要把数据输入到电子制表软件中),但关于可视化查抄或打印输出,就不是一个漂亮的显示格局.回想前面的process_result_set() 版本,产生过这样的输出:
? ? 让我们在每列加上标题和边框来对process_result_set() 做些改正,以生成表格局的输出.这种改正版看上去更美好,输出的后果是相同的,以下所示:
? ? 显示算法的基本要点是这样的:
? ? 1) 肯定每列的显示宽度.
? ? 2) 打印一列带有边框的列标题(由垂直竖线和前后的虚线脱离).
? ? 3) 打印后果集每行的值、带边框的列(由垂直竖线脱离),并垂直布列,除此之外,打印
? ? 精确的数字,将NULL 值打印为单词"NULL".
? ? 4) 最后,打印检索的行的计数.该操练为后果集元数据的利用供应了一个很好的示范.为了显示所描写的输出,除了行所包含的数据值之外,我们还需理解很多有关后果集的内容.您大概想,"这个描写听起来与mysql 显示的输出惊人地类似".是的,欢送把mysql 源代码和改正版的process_result_set() 代码对比一下,它们是差别的,可以发现对同一问题利用两种办法是有指导作用的.
? ? 首先,我们需求肯定每列的显示宽度,下面列出若何做这件事情.可察看到这些计算完好基于后果集元数据,无论行值是什么,它们都没有引用:
? ? 列宽度通过后果集合列的MYSQL_FIELD 构造的迭代来计算,调用mysql _ fetch _ seek( )定位第一个构造,后续的mysql_fetch_field() 调用返回指向持续列的构造的指针.显示出来的列宽度是下面三个值中的最大值,此中每一个都取决于列信息构造中的元数据:
? ? ■ field - > name的长度,也就是列标题的长度.
? ? ■ field - > max _ length,列中最长的数据值的长度.
? ? ■ 假如列中大概包含N U L L值,则为字符串" NULL"的长度,field->flag 表明列能否包含NULL.请注意,已知要显示的列的宽度后,我们将这个值赋给max _ length,max_length 是从客户机库获得的构造中的一个成员.这种获得是答应的吗?大概MYSQL_FIELD 构造的内容应当为只读?普通来说,是"只读的",但是MySQL 分发包中的一些客户机程序以一样的方法改变了max_length 的值,因此,假定这也是精确的(假如更喜好不改变max_length 值的办法,则分配一个unsigned int 值的数组,将计算的宽度存储到这个数组中).显示宽度的计算包含一个阐明,回想当利用mysql_use_result() 成立后果集时,max_length 没有意义.因为我们需求max_length 来肯定列值的显示宽度,所以该算法的精确操作需求利用mysql_store_result() 产生的后果集( MYSQL _ FIELD构造的length 成员奉告列值可以获得的最大值,假如利用mysql_store_result() 而不是mysql _ use _ result( )的话,这大概是个有效的工作环境).
? ? 一旦知道了列的宽度,便可以预备打印,处理标题很简单;关于给定的列,只需利用由field 指向的列信息构造,用已计算过的宽度打印出name 成员.
? ? 关于数据,我们对后果集合的行举行循环,在每次迭代时打印当前行的列值.从行中打印列值有些本领,因为值大概是N U L L,也大概代表一个数(无论哪类情形都照实打印).列值的打印以下,这里row[i] 包含数据值和指向列信息的field 指针:
? ? 假如field->type 指明的列范例是数字型,如INT、FLOAT大概DECIMAL,那么宏IS _ NUM的值为真.显示该后果集的终究的代码以下所示.注意,因为我们需求多次打印虚线,所以这段代码封装在它自己的函数中,函数print_dashes() 是这样的:
? ? MySQL 客户机库供应了拜候列信息构造的几种办法,比方,前面样例的代码多次利用以下情势的循环拜候这些构造:
? ? 但是,mysql_field_seek() 与mysql_fetch_field() 的结合是得到MYSQL_FIELD 构造的唯一途径,可在附录F 中查看mysql_fetch_field() 函数和mysql_fetch_field_direct() 函数,探求其他得到列信息构造的办法.
以上是“MySQL数据库技术(34)[MySQL防范]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
本文地址: | 与您的QQ/BBS好友分享! |