|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
由于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_affected_rows()找出有几行必要拔出、删除或修正。上面的样例申明怎样处置不前往了局集的查询:
请注重在打印时mysql_affected_rows()的了局是怎样转换为unsignedlong范例的,这个函数前往一个my_ulonglong范例的值,但在一些体系上没法间接打印这个范例的值(比方,笔者察看到它可在FreeBSD下事情,但不克不及在Solaris下事情)。把值转换为unsignedlong范例并利用‘%lu’打印格局能够办理这个成绩。一样也要思索前往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指针,失利则前往NULL。稍后我们将检察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的局限是从0到该行的列数减1。这里有几个关于MYSQL_ROW数据范例的要点必要注重:
■MYSQL_ROW是一个指针范例,因而,必需声明范例变量为MYSQL_ROWrow,而不是MYSQL_ROW*row。
■MYSQL_ROW数组中的字符串是空闭幕的。可是,列大概含有二进制数据,如许,数据中便可能含有空字节,因而,不该该把值当作是空闭幕的。由列的长度可知列值有多长。
■一切数据范例的值都是作为字符串前往的,即便是数字型的也是云云。假如必要该值为数字型,就必需本人对该字符串举行转换。
■在MYSQL_ROW数组中,NULL指针代表NULL,除非声明列为NOTNULL,不然应当常常反省列值是不是为NULL指针。
使用程序能够使用每行的内容做任何想做的事,为了举例申明这一点,我们只打印由制表符离隔列值的行,为此还必要别的一个函数,mysql_num_fields(),它来自于客户机库;这个函数告诉我们该行包含几个值(列)。
上面就是process_result_set()的代码:
process_result_set()以制表符分开的情势打印每行(将NULL值显现为单词“NULL”),它跟在被检索的行计数的前面,该计数经由过程挪用mysql_num_rows()来盘算。像mysql_affected_rows()一样,mysql_num_rows()前往my_ulonglong值,因而,将值转换为
unsignedlong型,并用‘%lu’格局打印。
提取行的轮回紧接在一个毛病查验的前面,假如要用mysql_store_result()创立了局集,
mysql_fetch_row()前往的NULL值一般意味着“不再有行”。但是,假如用mysql_use_result()创立了局集,则mysql_fetch_row()前往的NULL值一般意味着“不再有行”大概产生了毛病。不管如何创立了局集,这个测试只同意process_result_set()检测毛病。
process_result_set()的这个版本是打印列值请求前提最低的办法,每种办法都有必定的弱点,比方假定实行上面的查询:
我们能够经由过程供应一些信息如列标签,及经由过程使这些值垂直分列,而使输入了局大度一点。为此,我们必要标签和每列所需的最宽的值。这个信息是无效的,但不是列数据值的一部分,而是了局集的元数据的一部分(有关数据的数据)。复杂归结了一下查询处置程序后,我们将在6.6.6节“利用了局集元数据”中给出较大度的显现格局。
打印二进制数据
对包括大概含有空字节的二进制数据的列值,利用‘%s’printf()格局标识符不克不及将它准确地打印;printf()但愿一个空闭幕串,而且直到第一个空字节才打印列值。关于二进制数据,最好用列的长度,以便打印完全的值,如能够用fwrite()或putc()。
6.6.3通用方针查询处置程序
后面先容的处置查询样例使用了语句是不是应当前往一些数据的常识来编写的。这是大概的,由于查询流动在代码外部:利用INSERT语句时,它不前往了局,利用SHOWTABLES语句时,才前往了局。
但是,不成能一直晓得查询用的是哪种语句,比方,假如实行一个从键盘键进或来历于文件的查询,则它多是任何的语句。不成能提早晓得它是不是会前往行。固然不想对查询做语法剖析来决意它是哪类语句,总之,其实不像看上往那样复杂。只看第一个单词是不敷的,由于查询也大概以正文语句入手下手,比方:
/*comment*/SELECT
侥幸的是不用过早地晓得查询范例就可以够准确地处置它。用MySQLCAPI可编写一个能很好地处置任何范例语句的通用方针查询处置程序,不管它是不是会前往了局。在编写查询处置程序的代码之前,让我们简述一下它是怎样事情的:
■公布查询,假如失利,则停止。
■假如查询乐成,挪用mysql_store_result()从服务器检索行,并创立了局集。
■假如mysql_store_result()失利,则查询不前往了局集,大概在检索这个了局集时产生毛病。能够经由过程把毗连处置程序传送到mysql_field_count()中,并检测其值来区分这两种情形,以下:
■假如mysql_field_count()非零,申明有毛病,由于查询应当前往了局集,但却没有。这类情形产生有多种缘故原由。比方:了局集大概太年夜,内存分派失利,大概在提取行时客户机和服务器之间产生收集中止。
这类历程略微有点庞大的地方就在于,MySQL3.22.24之前的初期版本中不存在mysql_field_count(),它们利用的是mysql_num_fields()。为编写MySQL任何版本都能运转的程序,在挪用mysql_field_count()的文件中都包括上面的代码块:
这就将对mysql_field_count()的一些挪用看做是比MySQL3.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.5mysql_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是不是存在,能够实行上面的查询:
SHOWTABLESLIKE"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,列中最长的数据值的长度。
■假如列中大概包含NULL值,则为字符串“NULL”的长度,field->flag标明列是不是包括NULL。请注重,已知要显现的列的宽度后,我们将这个值赋给max_length,max_length是从客户机库猎取的布局中的一个成员。这类猎取是同意的吗?大概MYSQL_FIELD布局的内容应当为只读?一样平常来讲,是“只读的”,可是MySQL分发包中的一些客户机程序以一样的体例改动了max_length的值,因而,假定这也是准确的(假如更喜好不改动max_length值的办法,则分派一个unsignedint值的数组,将盘算的宽度存储到这个数组中)。显现宽度的盘算包含一个申明,回忆当利用mysql_use_result()创立了局集时,max_length没成心义。由于我们必要max_length来断定列值的显现宽度,以是该算法的准确操纵必要利用mysql_store_result()发生的了局集(MYSQL_FIELD布局的length成员告诉列值能够获得的最年夜值,假如利用mysql_store_result()而不是mysql_use_result()的话,这多是个有效的事情情况)。
一旦晓得了列的宽度,就能够筹办打印,处置题目很简单;关于给定的列,只需利用由field指向的列信息布局,用已盘算过的宽度打印出name成员。
关于数据,我们对了局会合的行举行轮回,在每次迭代时打印以后行的列值。从行中打印列值有些技能,由于值多是NULL,也大概代表一个数(不管哪一种情形都照实打印)。列值的打印以下,这里row包含数据值和指向列信息的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()函数,寻觅其他取得列信息布局的办法。有的时候,一些缺失的功能可以通过别的办法来实现,例如,在MySQL4.1以前,你可以通过使用join方法来替代子查询的功能。在MySQL5.0中,大多数关系型数据库所要求的功能已经都具备。 |
|