数据库编程,怎么学习c语言开发

语言 6
数据库编程 对于计算机应用来讲,科学计算进入到数据处理是一个划时代的转折。
这个转折使计算机从少数科学家手中的珍品转变成为科技人员和管理人员甚至普通用户的得力助手和有力工具。
几乎所有的应用程序都要存储数据。
数据的范围很广,从少量的程序运行参数到巨大的复杂数据库,比如全国人口普查信息、一个公司一年的营业收入等。
数据处理是指对各种形式的数据进行收集、存储、加工和传播的一系列活动的总和,其目的是从大量的原始数据中抽取并推导出对人们有价值的信息作为行动和决策的依据,并借助计算机科学地保存和管理大量复杂的数据,以充分而方便地利用信息资源。
数据处理的中心问题是数据管理。
数据管理是指对数据的收集、存储、检索和维护。
数据管理随着计算机硬件和软件的发展而不断发展。
40多年来数据管理经历了如下三个阶段:人工管理阶段、文件系统阶段和数据库系统阶段。
数据库系统是当代计算机系统的重要组成部分。
数据库技术所研究的问题就是如何科学地组织和存储数据,如何高效地获取、更新和加工数据,并保证数据的安全性、可靠性和持久性。
Linux的数据库功能很强,它常被用于数据库服务器端,因此有必要了解Linux数据库开发方面的知识。
本章将以MySQL为例讲述数据库开发的一些基础知识,让读者对数据库的开发有一个基本认识。
在介绍MySQL数据库开发之前,先介绍一些数据库的基础知识。
9.1数据库基本概念 在系统地了解数据库知识之前,应先了解和熟悉数据库的一些最基本的术语和概念: 数据、数据库、数据库管理系统、数据库语言和数据库系统。
9.1.1数据与数据库
1.数据(Data)数据是数据库中存储的基本对象。
在计算机中可表示数据的种类很多,文字、图形、图像、声音都可以数字化。
为了了解世界、交流信息,人们需要通过计算机来描述、存储和处理这些表现形式多样和内容复杂的数据。
可以对数据作如下定义:描述事物的符号记录称为“数据”。
描写事物的符号可以是数字,也可以是文字、图形、图像和声音等,即有多种表现形式,但它们都是经过数字化后存入计算机的。

2.数据库(DataBase,缩写为DB)数据库可以直观地理解为存放数据的仓库,这个仓库在计算机的大容量存储器上(如硬盘等)。
数据必须按照一定的格式存放,以便于查找。
可以认为数据库是被长期存放在计算机内、有组织的、可以表现为多种形式的可共享的数据集合。
数据库技术使得数据能够按一定格式组织、描述和存储,而且具有较小的冗余度、较高的数据独立性和易扩展性,并可为多个用户所共享。
9.1.2数据库管理系统 数据库管理系统(DataBaseManagementSystem,缩写为DBMS)是位于用户与操作系统之上的一层数据管理软件。
数据库管理系统是为数据库的建立、使用和维护而配置的软件。
它建立在操作系统的基础上,对数据库进行统一的管理和控制。
用户使用的各种数据库命令以及应用程序的执行,都要通过数据库管理系统。
数据库管理系统还承担着数据库的维护工作。
数据库管理系统的主要功能包括以下几个方面。

1.数据库定义功能DBMS一般提供数据定义语言(DDL),分别定义外模式、模式和内模式。
各种模式翻译程序把各种源模式翻译为相应的内部表示,分别称为目标外模式、目标模式和目标内模式。
这些目标模式是对数据库的定义,而不是数据本身。
它们刻画了数据库的框架,是DBMS存取和管理数据的基本依据。

2.数据存取功能DBMS提供数据操纵语言(DML),从而实现对数据库数据的基本操作:检索、插入、修改和删除。
DBMS控制并执行DML语言,完成对数据库的操作。
344 数据库编程第9章
3.数据库运行管理这是DBMS运行时的核心部分,包括安全性检查、完整性约束条件的检查和执行、数据库内部的维护等。
所有数据库的操作都要在这些控制程序的统一管理下进行,以保证事务的正确运行和数据库的正确有效。

4.数据库的建立和维护功能主要包括数据库初始数据的载入和转换、数据库的存储和恢复、数据库的重组、性能监视和分析等功能。
9.1.3数据库语言 数据库语言一般可分为以下两种:一种是交互式命令语言,它具有语法简明、可独立使用等特点;另一种则嵌入到某种程序设计语言中(如
C、FORTRAN、PASCAL、COBOL等),称为宿主型语言。
9.1.4数据库系统 数据库系统(DataBaseSystem,缩写为DBS)通常是指带有数据库的计算机应用系统,它不仅包括数据库本身(即实际存储在计算机中的数据),还包括相应的硬件、软件等。
9.1.5主要数据模型 数据库领域中过去和现在最常见的数据模型有三种,它们分别是:层次模型(HierachicalModel)、网状模型(NetworkModel)和关系模型(RelationalModel)。
其中层次模型和网状模型统称为非关系模型,在关系模型出现以前,它们是常用的数据模型。
关系模型是数据库领域所讨论的模型中最重要的模型。
自20世纪80年代以来,计算机厂商所推出的数据库管理系统的产品几乎都支持关系模型。
在用户看来,关系模型中数据库的逻辑结构(即数据结构)就是一张二维表。
用二维表结构来表示实体及实体间联系的模型就称为关系模型。
关系模型与以往的非关系模型最大的区别在于,它是建立在严格的数学概念基础之上的,其概念简单清晰,数据库语言易懂易学,用户无需了解复杂的存取路径细节,不需要说明“怎么做”,只需指出“做什么”,就能操作数据库,因此深得用户的青睐和喜爱,并涌现出许多性能良好的商业化关系数据库管理系统(RDBMS),如著名的Oracle、Informix、Sybase、MySQL等。
而且关系数据库产品也从单一的集中式系统发展到可在网络环境下运行的分布式系统,从封闭式系统逐步发展到开放式系统,从联机事务处理到支持信息管理、辅助决策,系统的功能不断完善,数据库的应用领域迅速扩大。
345 9.2SQL语言简介 SQL是英文(StructuredQueryLanguage)的缩写,意思为结构化查询语言。
SQL语言的主要功能就是同各种数据库建立联系,进行沟通。
按照ANSI(美国国家标准协会)的规定,SQL被作为关系型数据库管理系统的标准语言。
SQL语句可以用来执行各种各样的操作,例如更新数据库中的数据,从数据库中提取数据等。
目前,绝大多数流行的关系型数据库管理系统(如Oracle,Sybase,MySQL等)采用了SQL语言标准。
虽然很多数据库都对SQL语句进行了再开发和扩展,但是包括Select,Insert,Update,Delete,Create以及Drop在内的标准的SQL命令仍然可以被用来完成几乎所有的数据库操作。
下面,我们就来详细介绍一下SQL语言的基本知识。
9.2.1数据库表格 一个典型的关系型数据库通常由一个或多个被称作表格的对象组成。
数据库中的所有数据或信息都被保存在这些数据库表格中。
数据库中的每一个表格都具有自己唯一的表格名称,都是由行和列组成,其中每一列包括了该列名称,数据类型,以及列的其他属性等信息,而行则具体包含某一列的记录或数据。
表9-1是一个名为学生成绩的数据库表格的实例。
姓名张三李军张明王东刘红 表9-1学生成绩的数据库表格 学号 语文成绩 048071 82 048072 95 048073 93 048074 89 048075 92 数学成绩8590928885 该表格中“姓名”、“学号”、“语文成绩”和“数学成绩”就是4个不同的列,而表格中的每一行则包含了具体的表格数据。
9.2.2数据查询 在众多的SQL命令中,select语句应该算是使用最频繁的。
Select语句主要被用来对数据库进行查询并返回符合用户查询标准的结果数据。
Select语句的语法格式如下: 346 数据库编程第9章 select列1[,列,…]from表名[where条件]; []表示可选项。
select语句中位于select关键词之后的列名用来决定哪些列将作为查询结果返回。
用户 可以按照自己的需要选择任意列,还可以使用通配符“*”来设定返回表格中的所有列。
位于from关键词之后的表格名称用来决定将要进行查询操作的目标表格。
where可选从句用来规定哪些数据值或哪些行将被作为查询结果返回或显示。
在where条件从句中可以使用以下一些运算符来设定查询标准,如表9-2所示。
运算符=><>=<=<> 表9-
2 where条件中的运算符含义等于大于小于大于等于小于等于不等于 select语句举例如下: select语文成绩,数学成绩from学生成绩where学号>048073 上面select语句的作用是从学生成绩表中,查询学号>048073的语文成绩和数学成绩。
9.2.3创建表格 SQL语言中的createtable语句被用来建立新的数据库表格。
Createtable语句的使用格式如下: createtabletablename(column1datatype[constraint],column2datatype[constraint],column3datatype[constraint]); 简单来说,创建新表格时,在关键词createtable后面加入所要建立的表格的名称,然后在括号内顺次设定各列的名称、数据类型,以及可选的限制条件等。
注意,所有的SQL语句在结尾处都要使用“;”符号。
使用SQL语句创建的数据库表格和表格中列的名称必须以字母开头,后面可以使用字母,数字或下划线,名称的长度不能超过30个字符。
注意,用户在选择表格名称时不要使用SQL语言中的保留关键词,如select,create,insert等作为表格或列的名称。
数据类型用来设定某一个具体列中数据的类型。
例如,在姓名列中只能采用varchar或char的数据类型,而不能使用number的数据类型。
SQL语言中较为常用的数据类型如 347 表9-3所示。
数据类型 char(size) varchar(size)number(size)number(size,d)date 表9-3SQL语言中常用的数据类型说明 固定长度字符串,其中括号中的size用来设定字符串的最大长度。
Char类型的最大长度为255字节可变长度字符串,最大长度由size设定数字类型,其中数字的最大位数由size设定数字类型,size决定该数字总的最大位数,而d则用于设定该数字在小数点后的位数日期类型 最后,在创建新表格时需要注意的一点就是表格中列的限制条件。
所谓限制条件就是当向特定列输入数据时所必须遵守的规则。
例如,unique这一限制条件要求某一列中不能存在两个值相同的记录,所有记录的值都必须是唯一的。
除unique之外,较为常用的列的限制条件还包括notnull和primarykey等。
Notnull用来规定表格中某一列的值不能为空。
Primarykey则为表格中的所有记录规定了唯一的标识符。
createtable语句的用法举例如下: createtablestudent(firstnamevarchar(15),lastnamevarchar(20),agenumber
(3),addressvarchar(30),cityvarchar(20)); 上面createtable语句的作用是创建名为student的表格,表格中各列的名称分别为firstname、lastname、age、address、city。
它们的数据类型分别是varchar、varchar、number、varchar、varchar。
它们的最大位数分别为15、20、3、30、20。
9.2.4向表格中插入数据 SQL语言使用insert语句向数据库表格中插入或添加新的数据行。
Insert语句的使用格式如下: insertinto表名(第1列,...最后一列)values(第1个值,...最后一个值); 当向数据库表格中添加新记录时,在关键词insertinto后面输入所要添加的表格名称,然后在括号中列出将要添加新值的列的名称。
最后,在关键词values的后面按照前面输入的列的顺序对应地输入所有要添加的记录值。
例如: insertintoemployee(firstname,lastname,age,address,city)values(‘Li’,‘Ming’,45,‘No.77ChanganRoad’,‘Beijing”); 以上insert语句的作用是向employee表格中插入一条firstname='Li', 348 数据库编程第9章 lastname='Ming',age='45',addrss='No.7ChanganRoad',city='Beijing'的新记录。
9.2.5更新记录 SQL语言使用update语句更新或修改满足规定条件的现有记录。
Update语句的格式为: updatetablenamesetcolumnname=newvalue[,nextcolumn=newvalue2...]wherecolumnnameOPERATORvalue[and|orcolumnOPERATORvalue]; 使用update语句时,关键一点就是要设定好用于进行判断的where条件从句。
例如: updateemployeesetage=age+1wherefirstname='Mary'andlastname='Williams'; 上面语句的作用是把firstname='Mary'且lastname='Williams'的记录中的age更新为age+
1。
9.2.6删除记录 SQL语言使用delete语句删除数据库表格中的行或记录。
delete语句的格式为: deletefromtablenamewherecolumnnameOPERATORvalue[and|orcolumnOPERATORvalue]; 当需要删除某一行或某个记录时,在deletefrom关键词之后输入表格名称,然后在where从句中设定删除记录的判断条件。
注意,如果用户在使用delete语句时不设定where从句,则表格中的所有记录将全部被删除。
例如: deletefromemployeewherelastname=May; 以上delete语句的作用是删除lastname='May'对应的所有记录。
9.2.7删除数据库表格 在SQL语言中使用droptable命令删除某个表格以及该表格中的所有记录。
droptable命令的使用格式为: droptabletablename; 如果用户希望将某个数据库表格完全删除,只需要在droptable命令后输入希望删除的表格名称即可。
droptable命令的作用与删除表格中的所有记录不同。
删除表格中的全部记录之后,该表格仍然存在,而且表格中列的信息不会改变。
而使用droptable命令则会将整个数据库表格的所有信息全部删除。
例如: droptableemployee; 349 上述droptable语句将完全删除employee数据库表格。
以上,我们对SQL语言主要的命令和语句进行了较为详细的介绍。
在后面的编程中还会用到。
9.3MySQL数据库 MySQL是一个精巧的SQL数据库管理系统,虽然它不是开放源代码的产品,但在某些情况下可以自由使用。
由于具有功能强大、灵活性好、提供丰富的应用编程接口(ApI)的特点以及精巧的系统结构,MySQL受到了广大自由软件爱好者甚至商业软件用户的青睐,特别是其与Apache和PHP/PERL的组合,为建立基于数据库的动态网站提供了强大动力。
9.3.1MySQL的安装 安装MySQL非常简单。
对很多的平台来说,如果你的Linux安装没有复制的话,MysQL网站()拥有源代码以及预先编译好的二进制文件供下载。
通常来说尽管可以使用源代码安装,但是最好找到一个预先编译好的安装。
在Ubuntu下安装MySQL,可以在终端提示符后运行下列命令: $sudoapt-getinstallmysql-servermysql-client 一旦安装完成,MySQL服务器应该自动启动。
可以在终端提示符后运行以下命令来检查MySQL服务器是否正在运行: $stat-tap|grepmysql 当运行该命令时,可以看到类似下面的行: tcp
0 0localhost:mysql *:* 4598/mysqld LISTEN 如果服务器不能正常运行,可以通过下列命令启动它: $sudo/etc/init.d/mysqlrestart 默认的MySQL安装之后根用户(系统管理员root)是没有密码的,在第一次用根用户登录时,MySQL会强制你为根用户设定一个密码,在终端提示符后输入下列命令: $mysql-uroot-p 350 数据库编程第9章 这时系统会提示: Enterpassword: 这时输入的密码即为根用户的密码。
然后就可以进入到mysql中: etotheMySQLmonitor.Commandsendwith;or\g.YourMySQLconnectionidis17Serverversion:5.0.45-Debian_1ubuntu3.1-logDebianetchdistribution Type'help;'or'\h'forhelp.Type'\c'toclearthebuffer. mysql> 在mysql提示符后输入quit或\q即可推出mysql。
mysql>quitBye 在设定了根用户的密码后,再次以根用户登录时,除非提供用户和口令,否则没法运行mysql,正确的命令如下: $mysql-uroot-ppasswordmysql 注意,这里的语法有一点特殊,-p和口令之间没有空格。
最后一个参数mysql是所选的数据库。
如果不提供口令,只输入-p,mysql将会提示请给出一个口令。
由于在命令行中输入口令并不十分妥当(别人可以用ps指令等方法来得到这个口令),所以更好的方法是省略口令,使用这个格式: $mysql-uroot-pmysql 然后mysql将会提示请提供口令。
一旦运行了mysql,就可以检验一下当前的测试数据库,方法是在mysql提示符下输入: mysql>selecthost,db,userfromdb; 然后将会得到下面形式的列表: +------+---------+------+ |host|db |user| +------+---------+------+ |%|test| | |%|test\_%| | +------+---------+------+ 2rowsinset(0.00sec) 351 9.3.2MySQL管理 MySQL自带了少量实用程序,以便于管理这个系统。
在编写MysQL客户程序以前,需简要地浏览一下这些实用程序。
9.3.2.1命令 所有命令都有三个标准参数:-uUsername–p[Password]–hhost。
-u参数用于输入登录mysql的用户,-h参数用于在不同的主机上连接一台服务器,对于本地服务器则此参数可以省略。
如果给出-p却不提供口令的话,则会提示输入口令。
如果没有-p参数,则MySQL命令假设为不需要口令。
1.mysql这是标准命令行工具,可以用于以后将要涉及到的很多管理和权限任务。
mysql命令需要一个附加的参数,就是在选项后面加上需要连接的数据库名称。
例如,对于密码为bar的用户rick,为了用mysql开启选定的数据库foo,需要输入: $mysql-urick-pbarfoo 通常用这种方法可以很容易地指定要连接的数据库。
可以通过用-h选项打开mysql的方法来显示其他的选项。
2.mysqladminmysqladmin是主要的管理实用程序。
除了通用的-uuser以及-p来提示输入口令以外,还有几个主要的命令选项,如表9-4所示。
命令createdbnamedropdbnameflush-tablespasswordnewpasswordshutdownstatusvariablesversion 表9-4mysqladmin其他命令选项说明 创建一个名为dbname的新数据库删除dbname数据库清洗所有的表用newpassword变更原有口令关掉MySQL服务器给出服务器的简短状态信息打印出所有可用变量给出服务器的版本信息 例如: $mysqladmin-uroot-pstatus 352 数据库编程第9章 执行上述命令,输入口令后,系统显示如下: Uptime:4635Threads:1Questions:86Slowqueries:0Opens:23Flushtables:1Opentables:17Queriespersecondavg:0.019 若要查看服务器版本信息,可以输入如下命令: $mysqladmin-uroot-pversion 输入口令后,系统显示: mysqladminVer8.41Distrib5.0.45,forpc-linux-gnuoni486Copyright(C)2000-2006MySQLABThiseswithABSOLUTELYNOWARRANTY.Thisisfreesoftware,andyouareetomodifyandredistributeitundertheGPLlicense ServerversionProtocolversionConnectionUNIXsocketUptime: 5.0.45-Debian_1ubuntu3.1-log10 LocalhostviaUNIXsocket/var/run/mysqld/mysqld.sock1hour18min31sec Threads:1Questions:87Slowqueries:0Opens:23Flushtables:1Opentables:17Queriespersecondavg:0.018 更改根用户的口令: $mysqladmin-uroot-ppasswordpass123 在系统提示输入原有口令后,root用户的口令将更改为pass123。
如果只以-uUsername的方式打开程序,mysqladmin会提供一个详细的命令列表,读者可以参考。
3.mysqldumpmysqldump可以将一个数据库(所有的表或选定的表)导出到一个文件中,它的基本用法是: mysqldump[OPTIONS]database[tables] 除了基本的-u和-p选项外,常用的其他选项如表9-5所示。
命令--add-locks--add-drop-table--allow-keywords-c,plete-insert 表9-5mysqldump其他命令选项说明 在每个表导出之前锁定表并且之后解锁表在每个create语句之前增加一个droptable允许创建包含关键字的列使用完整的insert语句 353 命令-C,press--delayed-d,--no-data-t,--no-create-info--help 说明如果客户和服务器均支持压缩,压缩2者间的所有信息用INSERTDELAYED命令插入行不写入表的任何行信息,只导出表结构不写入表创建信息(CREATETABLE语句)显示帮助信息 (续表) mysqldump的输出信息在终端上显示,可将它重新定位到文件中。
使用这个实用程序可以对mysql数据库进行定期的备份,或者输出数据以便移到另一个数据库中。
输出的格式是直接ASCII格式,非常易于阅读;不仅如此,输出的内容中还结合有注释内容。
例如,将数据库testdb导出到文件testdb.bak中,用下面的命令: $mysqldump-uroot-ptestdb>testdb.bak 导出成功后,testdb.bak的内容如下所示: --MySQLdump10.11 -- --Host:localhostDatabase:testdb -------------------------------------------------------- --Serverversion 5.0.45-Debian_1ubuntu3.1-log /*!
40101SET@OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT*/;/*!
40101SET@OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS*/;/*!
40101SET@OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION*/;/*!
40101SETNAMESutf8*/;/*!
40103SET@OLD_TIME_ZONE=@@TIME_ZONE*/;/*!
40103SETTIME_ZONE='+00:00'*/;/*!
40014SET@OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS,UNIQUE_CHECKS=0*/;/*!
40014SET@OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS,FOREIGN_KEY_CHECKS=0*/;/*!
40101SET@OLD_SQL_MODE=@@SQL_MODE,SQL_MODE='NO_AUTO_VALUE_ON_ZERO'*/;/*!
40111SET@OLD_SQL_NOTES=@@SQL_NOTES,SQL_NOTES=0*/; ---Tablestructurefortable`children`-- DROPTABLEIFEXISTS`children`;CREATETABLE`children`( 354 数据库编程第9章 `childno`int(11)NOTNULLauto_increment,`fname`varchar(30)defaultNULL,`age`int(11)defaultNULL,PRIMARYKEY(`childno`))ENGINE=MyISAMAUTO_INCREMENT=3DEFAULTCHARSET=latin1; ---Dumpingdatafortable`children`-- LOCKTABLES`children`WRITE;/*!
40000ALTERTABLE`children`DISABLEKEYS*/;INSERTINTO`children`VALUES(
1,'Jenny',14),(
2,'Jack',12);/*!
40000ALTERTABLE`children`ENABLEKEYS*/;UNLOCKTABLES;/*!
40103SETTIME_ZONE=@OLD_TIME_ZONE*/; /*!
40101SETSQL_MODE=@OLD_SQL_MODE*/;/*!
40014SETFOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS*/;/*!
40014SETUNIQUE_CHECKS=@OLD_UNIQUE_CHECKS*/;/*!
40101SETCHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT*/;/*!
40101SETCHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS*/;/*!
40101SETCOLLATION_CONNECTION=@OLD_COLLATION_CONNECTION*/;/*!
40111SETSQL_NOTES=@OLD_SQL_NOTES*/; --pletedon2008-05-243:38:45 4.mysqlimport这个实用程序是伴随着mysqldump一起的。
它可以使数据库从文本文件中被重新创建。
通常这些文本文件是由mysqldump创建的,通常所需要的参数仅仅是数据库名称以及要读取命令的文本文件名称。
5.mysqlshow这是一个非常便利的实用小程序,它根据所设定的参数显示服务器、数据库或者表的信息。
●没有参数时,它将列出所有可用的数据库。
●参数是一个数据库时,它将列出这个数据库中所有的表。
●参数是一个数据库以及一个表名称时,它将列出这个表中的列。
●参数是数据库、表和列时,它将列出指定列的信息。
通常提供列名称没有太大的意义,因为在表级别上可以显示每一列的信息。
如显示所有的数据库,命令如下: 355 $mysqlshow-uroot-p 执行后,系统显示如下: +--------------------------+ | Databases | +--------------------------+ |information_schema| |mysql | |testdb | +--------------------------+ 可以看出系统中共有3个数据库,分别是:information_schema、mysql、testdb。
显示数据库testdb中所有的表: $mysqlshow-uroot–ptestdb 系统显示如下: Database:testdb+----------+|Tables|+----------+|children|+----------+ 可以看出,testdb中只有一个表children。
显示testdb中children表中的所有列: $mysqlshow-uroot-ptestdbchildren 系统显示如图9-1所示。
图9-1显示testdb中children表中的所有列 9.3.2.2创建用户并提供权限除了备份重要数据外,最常进行的管理工作就是设置用户权限了。
从MySQL的3.22 版本开始,用户权限通过两个SQL命令来管理:grant和revoke。
这两个指令实质是通过操作user(连接权限和全局权限)、db(数据库级权限)、tables_priv(数据表级权限)、columns_priv(数据列级权限)四个权限表来分配权限的。
host权限表不受这两个指令影响。
356 数据库编程第9章 下面将会详细介绍用户权限管理的内容。
这两个命令都在mysql命令程序中运行。
1.grantMySQL的grant命令类似于SQL92的标准,但仍然有显著的区别,通常的格式为: GRANTprivileges(columns)ONwhatTOountIDENTIFIEDBY'password'REQUIREencryptionrequirementsWITHgrantorresourcemanagementoptions; 其中,privileges表示授予的权限,mysql中的权限如表9-6所示。
columns表示作用的列(可选),what设置权限级别可以是全局级、数据库级、数据表级和数据列级,ount是权限授予的用户,用"user_name"@"host_name"这种用户名、主机名格式,IDENTIFIEDBY'password'设置用户账号口令,REQUIREencryptionrequirements设置经由SSL连接账号,WITHgrantorresourcemanagementoptions设置账号的管理和资源(连接服务器次数或查询次数等)选项。
权限CREATETEMPORARYTABLEFILEGRANTOPTIONLOCKTABLESPROCESSRELOADREPLICATIONCLIENTREPLICATIONSLAVESHOWDATABASESSHUTDOWNSUPERALTERCREATEDELETEDROPINDEXINSERTSELECTUPDATEALLUSAGE 表9-6mysql中的权限说明 创建临时数据表操作系统文件可把本账号的权限授予其他用户锁定指定数据表查看运行着的线程信息重新加载权限表或刷新日志及缓冲区可查询主/从服务器主机名运行一个镜像从服务器可运行SHOWDATABASES指令关闭数据库服务器可用kill终止线程以及进行超级用户操作可修改表和索引的结构创建数据库和数据表删除数据表中的数据行删除数据表和数据行建立或删除索引插入数据行查询数据行更新数据行所有权限,但不包括GRANT无权限 357 由ON子句设置的权限作用范围如表9-7所示。
权限限定符*.* * dbname.*dbname.tablenametablename 表9-7mysql中的权限作用范围说明 全局级权限,作用于所有数据库全局级权限,若未指定默认数据库,其作用范围是所有数据库,否则,其作用范围是当前数据库数据库级权限,作用于指定数据库里的所有数据表数据表级权限,作用于数据表里的所有数据列数据表级权限,作用于默认数据库中指定的数据表里的所有数据列 例如: mysql>grantallondb.*to'test'@'localhost'identifiedby'test'; 运行上述命令后,test用户只能通过'test'密码从本机访问db数据库 mysql>grantallondb.*to'test'%'localhost'identifiedby'test'; 运行上述命令后,test用户可通过‘test’密码从任意计算机上访问db数据库。
其中,'%'代表任意字符,'_'代表一个任意字符。
主机名部分还可以是IP地址。
如果没有给定主机部分,则默认为任意主机,也就是'test'和'test'@'%'是等价的。
USAGE权限通常用来修改与权限无关的账户项,如: mysql>GRANTUSAGEON*.*TOountIDENTIFIEDBY'new_password'; 上述命令的作用是修改密码。
mysql>GRANTUSAGEON*.*TOountREQUIRESSL; 上述命令启用SSL连接。
拥有WITHGRANTOPTION权限的用户可把自己所拥有的权限转授给其他用户,如: mysql>GRANTALLONdb.*TO'test'@'%'IDENTIFIEDBY'password'WITHGRANTOPTION; 这样test用户就有权把该权限授予其他用户。
GRANT也可以限制资源使用,如: mysql>GRANTALLONdb.*TOountIDENTIFIEDBY'password'WITHMAX_CONNECTIONS_PER_HOUR10MAX_QUERIES_PER_HOUR200MAX_UPDATES_PER_HOUR50; 允许ount用户每小时最多连接20次服务器,每小时最多发出200条查询命令(其中更新命令最多为50条)。
358 数据库编程第9章 默认都是零值,即没有限制。
FLUSHUSER_RESOURCES和FLUSHPRIVILEGES可对资源限制计数器清零。
2.revoke和deleterevoke用来取消权限,它的用法如下: mysql>REVOKEprivileges(columns)ONwhatFROMount; 各个选项的含义与grant中的相同。
例如: mysql>REVOKESELECTONdb.*FROM'test'@'localhost'; 执行上述命令后,将删除test账号从本机查询db数据库的权限。
REVOKE可删除权限,但不能删除账号,即使账号已没有任何权限。
所以user数据表里还会有该账号的记录,要彻底删除账号,需用DELETE命令删除user数据表的记录,如: mysql>DELETEFROMuserwhereUser='test'andHost='localhost';mysql>fulshprivileges; REVOKE不能删除REQUIRE和资源占用的配置。
他们是要用GRANT来删除的,如: GRANTUSAGEON*.*TOountREQUIRENONE;GRANTUSAGEON*.*TOountWITHMAX_CONNECTIONS_PER_HOUR0MAX_QUERIES_PER_HOUR0MAX_UPDATES_PER_HOUR0; 上述命令删除ount账号的SSL连接选项和ount账号的资源限制。
9.3.2.3口令 在创建新用户时,如果忘记指定口令,可以在后面对其进行设定。
首先以根用户登录,并选定mysql数据库。
输入下列查询语句: mysql>selecthost,user,passwordfromuser; 则会得到类似于图9-2所示的一张表。
图9-2查询user表 359 如果要为用户test1分配口令test的话,可以输入下列命令: mysql>updateusersetpassword=password('test')whereuser='test1'; 再次显示mysql.user表中的相关列: mysql>selecthost,user,passwordfromuser; 执行结果如图9-3所示。
图9-3user表的内容 可以看到,test1与我们在前面为用户test定义的加密口令是一样的。
9.3.2.4创建数据库 创建数据库的命令如下: createdatabasedbname; 其中,dbname是欲创建的数据库的名字。
例如,创建一个testdb的数据库: mysql>showdatabases; +------------------------+ |Database | +------------------------+ |information_schema| |mysql | +-------------------------+ 2rowsinset(0.01sec) mysql>createdatabasetestdb;QueryOK,1rowaffected(0.00sec) mysql>showdatabases;+-------------------------+ 360 数据库编程第9章 |Database | +-------------------------+ |information_schema| |mysql | |testdb | +-------------------------+ 3rowsinset(0.00sec) 其中,showdatabases;命令是查看系统中当前存在的数据库,可以看出在执行create命令后,成功地创建了testdb数据库。
然后切换使用use命令使用数据库testdb: mysql>usetestdbDatabasechanged 现在我们可以按照需要创建任何表。
首先看一下现在数据库中存在的表: mysql>showtables;Emptyset(0.00sec) 说明刚才建立的数据库中还没有数据库表。
下面来创建一个数据库表children,该表显示一个学校的儿童登记表,表的内容包含ID、儿童姓名、年龄。
命令如下: mysql>createtablechildren(childnoINTEGERAUTO_INCREMENTNOTNULLPRIMARYKEY,fnameVARCHAR(30),ageINTEGER); QueryOK,0rowsaffected(0.09sec) 由于fname的列值是变化的,因此选择VARCHAR,其长度不一定是30。
可以选择从1到255的任何长度,如果以后需要改变它的字长,可以使用ALTERTABLE语句。
创建了一个表后,看看刚才做的结果,用SHOWTABLES显示数据库中有哪些表: mysql>showtables; +---------------------+ |Tables_in_testdb| +---------------------+ |children | +---------------------+ 1rowinset(0.00sec) 可以用DESCRIBE查看表的结构,命令及显示结果如图9-4所示。
由于children为新建的表,还没有任何记录。
这可以通过下列查询命令看出: mysql>select*fromchildren;Emptyset(0.09sec) 361 图9-4显示表的结构 说明刚才创建的表还没有记录。
加入3条新记录,命令如下: mysql>insertintochildren(fname,age)values("Jenny",14);QueryOK,1rowaffected(0.05sec)mysql>insertintochildren(fname,age)values("John",10);QueryOK,1rowaffected(0.00sec)mysql>insertintochildren(fname,age)values("Jack",11);QueryOK,1rowaffected(0.00sec) 然后再次运行select命令,结果如图9-5所示。
图9-5select查询结果 可以按照上面的方法一条一条地将所有儿童的记录加入到表中。
以上我们简要介绍了MySQL数据库的安装和一些常用的使用方法,关于MySQL更详细的介绍,读者可以查阅MySQL的帮助手册。
下一节我们将介绍用C语言访问MySQL数据库的方法。
9.4用C语言访问MySQL数据库 MySQL可以用很多不同的语言进行访问,其中包括:
C、C++、Java、Perl、Python、PHP等。
在这一节,我们介绍用C语言访问MySQL数据库的方法。
362 数据库编程第9章 9.4.1连接数据库 安装了MySQL后,在/usr/include/mysql下,包含了用C语言操作MySQL所需的头文件:mysql.h。
其中定义了相关的数据结构,它们的意义如表9-8所示。
结构MYSQLMYSQL_RESMYSQL_ROWMYSQL_FIELD 表9-8mysql.h中定义的结构说明 连接句柄用来保存从数据库中检索出的列保存返回的其中一列数据库中的字段 用C语言向一个MySQL数据库的连接包括2步:
(1)初始化一个MYSQL结构。

(2)进行连接。
首先必须调用mysql_init连接初始化一个MYSQL结构,它的原型如下: #includeMYSQL*mysq_init(MYSQL*mysql); 其中,如果传递的参数为NULL,则初始化一个新的结构,分配新的内存空间,其他情况下将把mysql初始化。
函数成功返回初始化后的MYSQL结构指针,否则返回NULL。
在初始化MYSQL结构之后,接下来需要设置连接数据库的相关参数,可以用mysql_real_connect函数来设置这些参数,并进行实际的连接,它的原型如下: #includeMYSQL*mysql_real_connect(MYSQL*mysql,constchar*host,constchar*user,constchar*passwd, constchar*db,unsignedintport,constchar*unix_socket,unsignedintclient_flag); 其中,mysql指向刚才用mysql_init初始化的结构体。
host是MySQL服务器所在的服务器计算机的名称或者IP地址。
如果你要连接本地计算机,那么应该使用localhost,而不是计算机名,这样MySQL可以优化连接类型。
user以及passwd是数据库登录时的用户名和口令。
如果登录的用户名是NULL,则登录的用户名假定为当前的登录ID。
如果口令是NULL,则你只可以访问这个服务器中不需要口令的数据。
口令在传递到网络以前是加密的。
除非需要非标准值,否则端口号以及unix_socket的值分别为0和NULL。
这两个值是默认的。
client_flag值通常是
0,但是在很特殊的情况下可以被设置为下列标志的组合,如表 363 9-9所示。
选项CLIENT_FOUND_ROWSCLIENT_NO_SCHEMACLIENT_COMPRESSCLIENT_ODBC 表9-9client_flag选项说明 返回找到的(匹配的)行数,不是受到影响的行数不允许db_name.tbl_name.col_name语法,如果使用该语法,会导致语法分析器产生一个错误,它是为一些ODBC程序捕捉错误所使用的使用压缩协议客户是一个ODBC客户。
这使mysqld变得对ODBC更友好 mysql_real_connect函数成功返回一个指向MYSQL结构的指针,返回值与第一个参数值相同。
如果连接失败,返回NULL。
可以用mysql_error函数查看错误原因,下面会介绍这一函数。
在完成连接任务(通常在程序结束以后),可以用mysql_close来关闭连接,它的原型如下: #includevoidmysql_close(MYSQL*mysql); 这样就可以关闭连接。
参数mysql将被清空,指针也变为无效而不能重新使用。
与连接函数紧密关联(它只能在mysql_init和mysql_real_connect之间调用)的是mysql_options,原型如下: #includeintmysql_options(MYSQL*mysql,enummysql_optionoption,constchar*arg); mysql_options用于设置额外的连接选项,并影响连接的行为。
可多次调用该函数来设置数个选项。
应在mysql_init()之后、以及mysql_real_connect()之前调用mysql_options。
选项参量指的是打算设置的选项。
Arg参量是选项的值。
如果选项是整数,那么arg应指向整数的值。
常用的选项值如表9-10所示。
选项MYSQL_INIT_COMMANDMYSQL_OPT_CONNECT_TIMEOUTMYSQL_OPT_PROTOCOLMYSQL_OPT_COMPRESS 表9-10arg选项说明 连接到MySQL服务器时将执行的命令。
再次连接时将自动地再次执行以秒为单位的连接超时要使用的协议类型。
应是mysql.h中定义的mysql_protocol_type的枚举值之一在网络连接中使用压缩 364 数据库编程第9章 mysql_options成功调用返回
0,失败返回非0值。
例9-1下面的代码段将连接超时设定为7秒。
unsignedinttimeout=7;...MYSQL*connection=mysql_init(NULL);ret=mysql_options(connection,MYSQL_OPT_CONNECT_TIMEOUT,(constchar*)&timeout); if(ret){ /*错误处理*/...}connection=mysql_real_connect(connection,...); 以上我们已经知道了怎样对一个连接进行基本的设定以及怎样关闭它。
现在写一个短程序来验证一下。
例9-2连接MYSQL数据库。
1/*ex1.c*/ 2#include 3#include 4#include 5MYSQL*conn_ptr;
6 7intmain() 8{
9 conn_ptr=mysql_init(NULL); 10 if(!
conn_ptr) 11 { 12 fprintf(stderr,"mysql_initfailed!
\n"); 13 return-1; 14 } 15 conn_ptr=mysql_real_connect(conn_ptr,"localhost","test","test","testdb",
0,NULL,0); 16 if(conn_ptr) 17 printf("Connectioneed!
\n"); 18 else 19 { 20 printf("Connectionfailed!
\n"); 21 return-2; 22 } 23 mysql_close(conn_ptr); 24 printf("Connectionclosed.\n"); 365 2526} return0; 说明:上面的程序首先初始化一个MYSQL结构指针(第9~14行),然后连接本地MYSQL服务器,用户名是test,口令是test,连接的数据库是testdb(第15行),随后关闭连接,退出程序(第23~25行)。
由于要用到mysql库文件,因此在编译时需要指定,编译连接命令如下: -lmysqlclient-oex1ex1.c 本章后面的例子程序都要加-lmysqlclient参数,不再另行说明。
程序执行结果如下: $./ex1Connectioneed!
Connectionclosed. 可见,连接一个数据库是非常简单的。
9.4.2错误处理 在进入更有用的程序之前,我们需要看一下MYSQL是怎样处理错误的。
所有的错误都通过返回编码来指示,并且通过连接句柄结构体来报告细节。
有2个函数可以进行错误报告: #includeunsignedintmysql_errno(MYSQL*mysql);constchar*mysql_error(MYSQL*mysql); 对于由mysql指定的连接,mysql_errno()返回最近调用的函数的错误代码,该函数调用可能成功也可能失败。
0返回值表示未出现错误。
在MySQLerrmsg.h头文件中,列出了客户端错误消息编号。
对于由mysql指定的连接,对于失败的最近调用的函数,mysql_error返回包含错误消息的、由Null终结的字符串。
如果该函数未失败,mysql_error的返回值可能是以前的错误,或指明无错误的空字符串。
例9-3mysql错误处理函数。
1/*ex2.c*/2#include3#include4#include56intmain() 366 数据库编程第9章 7{891011121314151617181920212223242526} MYSQLmy_connection;mysql_init(&my_connection);if(mysql_real_connect(&my_connection,"localhost","test","","testdb",
0,NULL,0)){ printf("Connectioneed.\n");mysql_close(&my_connection);}else{fprintf(stderr,"Connectionfailed.\n");if(mysql_errno(&my_connection)){ fprintf(stderr,"Connectionerror:%d%s\n",mysql_errno(&my_connection),mysql_error(&my_connection)); return-1;}}return0; 说明:例9-3与例9-2基本相同,不同的是在连接时,没用说明口令(第10行),因此mysql_real_connect函数会出错,随后用mysql_errno、mysql_error函数输出错误代码和错误提示信息(第18~23行)。
程序运行结果如下: $./ex2Connectionfailed.Connectionerror:1045essdeniedforuser'test'@'localhost'(usingpassword:YES) 从错误提示信息可以看出,是由于口令不正确导致连接失败。
9.4.3执行SQL语句 我们已经有一个连接,并且知道怎样处理错误,那么现在就可以做一些关于数据库的实际工作了。
执行SQL语句的函数是mysql_query: #includeintmysql_query(MYSQL*mysql,constchar*query); mysql_query函数将一个指针指向一个连接结构,并且执行包含SQL的文本字符串。
与命令行工具不同,它没有用来表示终止的分号。
如果运行成功,函数返回
0,失败返回非
0,可能的错误信息如表9-11所示。
367 表9-10mysql_query错误信息 选项 说明 CR_COMMANDS_OUT_OF_SYNC 以不恰当的顺序执行了命令 CR_SERVER_GONE_ERROR MySQL服务器不可用 CR_SERVER_LOST 在查询过程中,与服务器的连接丢失 CR_UNKNOWN_ERROR 出现未知错误 对于SQL语句,可以包含以下几种情况:9.4.3.1不返回数据的SQL语句 这些语句包括UPDATE、DELETE以及INSERT语句。
由于它们不从数据库返回数据,因此更容易学习。
另一个需要介绍的重要函数是用来检验受影响的行数量的函数: #includemy_ulonglongmysql_affected_rows(MYSQL*mysql) 这个函数返回上次UPDATE更改的行数,上次DELETE删除的行数或上次INSERT语句插入的行数。
对于UPDATE、DELETE或INSERT语句,可在mysql_query后立刻调用。
出于可移植性的原因,这个结果是没有符号的。
在用于printf的时候,推荐设定类型为无符号的长数据,用%lu来指定这个格式。
下面看一个例子。
例9-4查看SQL语句改动的行数量。
1/*ex3.c*/ 2#include 3#include
4 5#include
6 7intmain() 8{
9 MYSQLmy_connection; 10 intres; 11 mysql_init(&my_connection); 12 if(mysql_real_connect(&my_connection,"localhost","test","test","testdb",
0,NULL,0)) 13 { 14 printf("Connectioneed.\n"); 15 res=mysql_query(&my_connection,"INSERTINTOchildren(fname,age) VALUES('Ann',3)"); 16 if(!
res) 368 数据库编程第9章 17 181920 2122232425262728293031 3233343536} printf("Inserted%lurows\n",(unsignedlong)mysql_affected_rows(&my_connection)); else{ fprintf(stderr,"Inserterror%d%s\n",mysql_errno(&my_connection),mysql_error(&my_connection)); return-1;}mysql_close(&my_connection);printf("Connectionclosed.\n");}else{fprintf(stderr,"Connectionfailed.\n");if(mysql_errno(&my_connection)){ fprintf(stderr,"Connectionerror:%d%s\n",mysql_errno(&my_connection),mysql_error(&my_connection));return-2;}}return0; 说明:这个程序与例9-3基本相同,在连接成功后,调用了mysql_query函数向testdb数据库的children表中插入了一条新的记录,并输出了插入的行数(第12~17行),其他部分与例9-3相同,在此不再赘述。
程序执行结果如下: $./ex3Connectioneed.Inserted1rowsConnectionclosed. 从执行结果可以看出,插入的行数为
1。
9.4.3.2返回数据的语句 下面我们要了解SQL最常用的功能,即用SELECT语句从数据库中检索数据。
通常从MySQL数据库中检索数据有4个步骤:
(1)发出查询。

(2)检索数据。

(3)处理数据。
369
(4)整理所需要的数据。
用mysql_query发出查询。
检索数据可以用mysql_store_result或者mysql_use_result,这取决于希望以何种方式检索数据,接着是调用mysql_fetch_row来处理数据。
最后必须调用mysql_free_result以允许MySQL进行必要的整理工作。
在单一的调用中使用SELECT(或者其他返回数据的语句)检索数据,方法是使用mysql_store_result,它的原型如下: #includeMYSQL_RES*mysql_store_result(MYSQL*mysql); 这个函数必须在mysql_query检索完数据以后才能调用,以用来在结果集合中存储数据。
此函数从服务器中检索所有的数据并将它立即存储在客户端。
它返回一个我们以前没有遇到过的结构体指针——结果集合结构体指针。
如果这个语句失败,则返回NULL值。
假如没有返回NULL值,则可以调用mysql_num_rows函数来检索实际返回的行数,这个数当然有可能为
0。
mysql_num_rows函数的原型如下: #includemy_ulonglongmysql_num_rows(MYSQL_RES*result); mysql_num_rows函数在结果集合中返回行的数量。
返回在结果集合中的行数有可能为
0。
如果mysql_store_result成功,则mysql_num_rows也将成功。
将mysql_store_result和mysql_num_rows结合来检索数据是非常简便和直观的方法。
一旦mysql_store_result返回成功,所有查询的数据都将存储在客户端,这样我们可以在结果结构体中查询这些数据,由于这些数据现在对于我们的程序而言是在当地,所以不需要冒更多数据库或网络出错的危险。
这样我们也可以及时发现返回的行数量,也可以使编码变得更简单。
像在前面提到过的一样,将立刻将结果返回给客户。
不过对于更大的结果集合而言,这种方法会大量地消耗服务器、网络、以及客户资源。
因此,如果我们要处理的是更大的数据集合,最好还是按照需要检索数据。
在检索到数据后需要对数据进行处理,可以用以下几个函数实现mysql_fetch_row、mysql_data_seek、mysql_row_tell、mysql_row_seek。
下面先看一下mysql_fetch_row函数,它的原型如下: #includeMYSQL_ROWmysql_fetch_row(MYSQL_RES*result) 这个函数获得从storeresult中得到的结果结构体,并从中检索单个行,返回分配的行结构体中的数据。
当没有更多的数据,或者出错时,将返回NULL值。
我们后面将回到这个行结构体中处理数据。
与mysql_fetch_row不同的是,mysql_data_seek函数在一个查询结果集合中定位任意行。
它的原型如下: 370 数据库编程第9章 #includevoidmysql_data_seek(MYSQL_RES*result,unsignedlonglongoffset); 这个函数允许用户进入结果集,设置将由下一个获取操作返回的行。
offset是行号,它必须在从0到结果集中的行数减1的范围内。
传递0将导致在下一次调用mysql_fetch_row时返回第一行。
mysql_row_tell函数的原型如下: #includeMYSQL_ROW_OFFSETmysql_row_tell(MYSQL_RES*result) 这个函数返回一个偏移值,它表示结果集中的当前位置。
它不是行号,不能将它用于mysql_data_seek。
但是,可将它用于mysql_row_seek: #includeMYSQL_ROW_OFFSETmysql_row_seek(MYSQL_RES*result,MYSQL_ROW_OFFSEToffset); mysql_row_seek移动结果集中的当前位置,并返回以前的位置。
有时,这一对函数对于在结果集中的已知点之间跳转很有用。
请注意,不要将mysql_row_tell和mysql_row_seek使用的偏移值与mysql_data_seek使用的行号混淆,这2个值是不能互换的。
检索数据最后一个需要了解的函数是mysql_free_result。
它的原型如下: #includevoidmysql_free_result(MYSQL_RES*result); 当已经完成一个结果集合时,则必须调用此函数以便MySQL库整理分配的对象。
以上介绍了从MySQL数据库中检索数据需要的几个函数,下面看一个例子。
例9-5从MySQL数据库中检索数据。
1/*ex4.c*/
2 #include
3 #include
4 #include
5 MYSQLmy_connection; 6MYSQL_RES*res_ptr; 7MYSQL_ROWsqlrow; 8intmain() 9{ 10 intres; 11 mysql_init(&my_connection); 12 if(mysql_real_connect(&my_connection,"localhost","test","test","testdb",
0,NULL,0)) 13 { 14 printf("Connectioness\n"); 371 15 res=mysql_query(&my_connection,"SELECTchildno,fname,ageFROM children 16 WHEREage>5"); 17 if(res) 18 { 19 printf("SELECTerror:%s\n",mysql_error(&my_connection)); 20 return-2; 21 } 22 else 23 { 24 res_ptr=mysql_store_result(&my_connection); 25 if(res_ptr) 26 { 27 printf("Retrieved%lurows\n",(unsignedlong)mysql_num_rows(res_ptr)); 28 while((sqlrow=mysql_fetch_row(res_ptr))) 29 printf("Fetcheddata...\n"); 30 if(mysql_errno(&my_connection)) 31 { 32 fprintf(stderr,"Retriveerror:s\n",mysql_error(&my_connection)); 33 return-3; 34 } 35 } 36 mysql_free_result(res_ptr); 37 } 38 mysql_close(&my_connection); 39 printf("Connectionclosed.\n"); 40 } 41 else 42 { 43 fprintf(stderr,"Connectionfailed\n"); 44 if(mysql_errno(&my_connection)) 45 { 46 fprintf(stderr,"Connectionerror%d:%s\n", 47 mysql_errno(&my_connection),mysql_error(&my_connection)); 48 return-1; 49 } 50 } 51 return0; 52} 说明:在上面的程序中首先初始化一个MYSQL结构(第47行),然后建立连接(第48行)。
在数据库testdb的children表中选定age大于5的行的内容(第51行)。
然后检索返回的结果集并循环通过已检索的数据,最后调用mysql_free_result函数使MySQL库整理分配 372 数据库编程第9章 的对象,关闭连接(第60~74行)。
程序的执行结果如下: $./ex4ConnectionessRetrieved3rowsFetcheddata...Fetcheddata...Fetcheddata...Connectionclosed. 为了按照需要逐行检索数据,而不是同时获取所有的数据并储存在客户端,可以用mysql_use_result代替mysql_store_result: #includeMYSQL_RES*mysql_use_result(MYSQL*result); 这个函数也是得到一个连接对象并返回一个结果集合指针,或者在出错时返回NULL。
与mysql_store_result一样,这将返回一个结果集合对象。
不过关键的是在返回时它实际上并没有将任何检索到的数据返回到结果集合中,而仅仅是将结果集合初始化来接收数据。
为了检索数据,必须和反复调用mysql_fetch_row,直到检索完所有的数据。
在使用mysql_use_result时,将不能使用函数mysql_num_row、mysql_data_seek、mysql_row_seek、mysql_rows_tell。
实际上这也不是非常严格:mysql_num_rows可以被调用,但是在mysql_fetch_result检索完之前不能返回可用行的数量。
这样它也就没什么太大用处了。
但是使用mysql_use_result时,降低了网络通信流量负载,显著减少了客户的过量信息存储。
对于较大的数据集合,用mysql_use_result逐行检索是较优越的一种方法。
例9-6用mysql_use_result检索数据。
1/*ex5.c*/ 2#include 3#include 4#include 5MYSQLmy_connection; 6MYSQL_RES*res_ptr; 7MYSQL_ROWsqlrow; 8intmain() 9{ 10 intres; 11 mysql_init(&my_connection); 12 if(mysql_real_connect(&my_connection,"localhost","test","test","testdb",
0,NULL,0)) 13 { 14 printf("Connectioness\n"); 15 res=mysql_query(&my_connection,"SELECTchildno,fname,ageFROM 373 children 16 WHEREage>5"); 17 if(res) 18 { 19 printf("SELECTerror:%s\n",mysql_error(&my_connection)); 20 return-2; 21 } 22 else 23 { 24 res_ptr=mysql_use_result(&my_connection); 25 if(res_ptr) 26 { 27 printf("Retrieved%lurows\n",(unsigned long)mysql_num_rows(res_ptr)); 28 while((sqlrow=mysql_fetch_row(res_ptr))) 29 printf("Fetcheddata...\n"); 30 if(mysql_errno(&my_connection)) 31 { 32 fprintf(stderr,"Retriveerror: s\n",mysql_error(&my_connection)); 33 return-3; 34 } 35 } 36 mysql_free_result(res_ptr); 37 } 38 mysql_close(&my_connection); 39 printf("Connectionclosed.\n"); 40} 41 else 42 { 43 fprintf(stderr,"Connectionfailed\n"); 44 if(mysql_errno(&my_connection)) 45 { 46 fprintf(stderr,"Connectionerror%d:%s\n", 47 mysql_errno(&my_connection),mysql_error(&my_connection)); 48 return-1; 49 } 50 } 51return0; 52} 说明:程序6同程序5基本相同,唯一的区别是用mysql_use_result函数代替了mysql_store_result函数(第24行)。
从程序执行结果也可以看出2者之间的差别: 374 数据库编程第9章 $./ex5ConnectionessRetrieved0rowsFetcheddata...Fetcheddata...Fetcheddata...Connectionclosed. 在得到结果以后并不能立即发现检索到的行数量。
而且前面提到的检错技巧——mysql_errno(&my_connection)在错误不出现时将为零——更加易于应用。
如果通过mysql_store_result编写代码,但是考虑到有可能需要回头转而使用mysql_use_result,可以在开始编码的时候记住这一点,然后通过检验所有函数返回的结果来保守地编码,这样会使此转换容易得多。
9.4.3.3处理返回的数据 除非能够做进一步的工作,否则仅是检索数据是没有什么用处的。
返回的数据有2种类型:
(1)从数据库中检索到的实际信息。

(2)关于数据的数据,所谓的“元数据”。
再确定列名称以及关于数据的其他信息,首先看一下怎样恢复数据并将数据打印。
可以使用mysql_field_cont函数,它得到一个连接对象并返回在结果集合中字段的数目: #includeunsignedintmysql_field_count(MYSQL*result); 这个函数也可以用于更普通的处理进程中,例如判断为何mysql_store_result调用失败。
如果mysql_store_result返回NULL,但是mysq1_fleId_count返回一个大于0的数,可以知道结果集合中应该有一些列,但是在检索它们的时候出现了错误。
另一方面,如果mysql_field_count返回
0,则是没有检索到列,这就是为什么试图存储数据失败的原因。
这更多地适用于预先不知道SQL语句或者希望编写一个完全通用的查询进程模块的情况。
如果仅仅希望在非格式化的文本格式中得到结果信息,那么现在已经足以将数据直接打印出来,使用的是从mysql_fetch_row中返回的MYSQL_ROW结构体。
可以添加—个非常简单的函数到例9-6程序中,来打印数据。
例9-7打印查询的数据。
1/*ex6.c*/2#include3#include4#include5MYSQLmy_connection; 375 6MYSQL_RES*res_ptr; 7MYSQL_ROWsqlrow; 8voiddisplay_row(MYSQL*ptr); 9intmain() 10{ 11 intres; 12 mysql_init(&my_connection); 13 if(mysql_real_connect(&my_connection,"localhost","test","test","testdb",
0,NULL,0)) 14 { 15 printf("Connectioness\n"); 16 res=mysql_query(&my_connection,"SELECTchildno,fname,ageFROMchildren WHERE 17 age>5"); 18 if(res) 19 { 20 printf("SELECTerror:%s\n",mysql_error(&my_connection)); 21 return-2; 22 } 23 else 24 { 25 res_ptr=mysql_use_result(&my_connection); 26 if(res_ptr) 27 { 28 printf("Retrieved%lurows\n",(unsignedlong)mysql_num_rows(res_ptr)); 29 while((sqlrow=mysql_fetch_row(res_ptr))) 30 { 31 printf("Fetcheddata...\n"); 32 display_row(&my_connection); 33 } 34 if(mysql_errno(&my_connection)) 35 { 36 fprintf(stderr,"Retriveerror:s\n",mysql_error(&my_connection)); 37 return-3; 38 } 39 } 40 mysql_free_result(res_ptr); 41 } 42 mysql_close(&my_connection); 43 printf("Connectionclosed.\n"); 44 } 45 else 46 { 47 fprintf(stderr,"Connectionfailed\n"); 376 数据库编程第9章 48 if(mysql_errno(&my_connection)) 49 { 50 fprintf(stderr,"Connectionerror%d:%s\n", 51 mysql_errno(&my_connection),mysql_error(&my_connection)); 52 return-1; 53 } 54 } 55 return0; 56} 57 58voiddisplay_row(MYSQL*ptr) 59{ 60 unsignedintfield_count; 61 field_count=0; 62 while(field_count在main函数的while循环中调用了display_row函数(第32行)。
程序输出结果如下: $./ex6ConnectionessRetrieved0rowsFetcheddata...1Jenny14Fetcheddata...2John10Fetcheddata...3Jack11Connectionclosed. 尽管实现的功能很基础,不过程序毕竟已经能够执行了。
我们没有考虑在结果中可能出现的NULL值。
如果想要在表格中显示输出,例如在一个更加结构化的表单中得到数据以及关于数据的信息的话,那么该怎样做?
需要一次性获取一个字段的信息,然后把其输入到一个包含数据和源数据(关于返回数据的数据)的结构体中去。
这需要通过mysql_fetch_fleld函数来实现: 377 #includeMYSQL_FIELD*mysql_fetch_field(MYSQL_RES*result); 这个函数返回作为MYSQL_FIELD结构的一个结果集合的列的定义。
重复调用这个函数在结果集合中检索所有关于列的信息。
当没有剩下更多的字段时,mysql_fetch_field()返回NULL。
指向返回的字段结构体的指针可以用来访问储存在字段结构体中列的各种信息。
字段内容由mysql.h所定义,如表9-11所示。
字段char*namechar*tablechar*defenumenum_field_typestypeunsignedintlength unsignedintmax_length unsignedintflagunsignedintdecimals 表9-11 MYSQL_FIELD结构体中的字段说明 列的名称,是一个字符串列所在的表名称,这在选择使用多个表的时候更有用如果调用mysql_list_fields,则包含列的默认值列的类型列的宽度,在定义表格的时候指定如果使用mysql_store_result,则它包含找到的最长的实际列长度。
如果使用mysql_use_result,则不会对它进行设置标识符。
告知关于列的定义,而与实际找到的数据无关十进制数,只对数字字段有效 下面介绍一个非常有用的宏IS_NUM,如果字段类型是数字形式的,则其返回值为真。
这个宏如下: if(IS_NUM(mysql_field_ptr->type))printf("Numerictypefield\n"); 在更新程序以前,再介绍一个函数mysql_field_seek: #includeMYSQL_FIELD_OFFSETmysql_field_seek(MYSQL_RES*result,MYSQL_FIELD_OFFSEToffset); 此函数将字段光标设置到给定的偏移量。
下一次调用mysql_fetch_field将检索与该偏移量关联的列的字段定义。
若要定位于行的起始,则要传递一个值为0的offset值。
下面看一个例子。
例9-8结构化的数据库查询输出。
1/*ex7.c*/2#include3#include4#include5MYSQLmy_connection;6MYSQL_RES*res_ptr; 378 数据库编程第9章 7MYSQL_ROWsqlrow; 8voiddisplay_header(); 9voiddisplay_row(MYSQL*ptr); 10intmain() 11{ 12 intres; 13 intfirst_row=1; 14 mysql_init(&my_connection); 15 if(mysql_real_connect(&my_connection,"localhost","test","test","testdb",
0,NULL,0)) 16 { 17 printf("Connectioness\n"); 18 res=mysql_query(&my_connection,"SELECTchildno,fname,ageFROMchildren 19 WHEREage>5"); 20 if(res) 21 { 22 printf("SELECTerror:%s\n",mysql_error(&my_connection)); 23 return-2; 24 } 25 else 26 { 27 res_ptr=mysql_use_result(&my_connection); 28 if(res_ptr) 29 { 30 display_header(); 31 while((sqlrow=mysql_fetch_row(res_ptr))) 32 { 33 if(first_row) 34 { 35 display_header(); 36 first_row=0; 37 } 38 display_row(&my_connection); 39 } 40 if(mysql_errno(&my_connection)) 41 { 42 fprintf(stderr,"Retriveerror:s\n",mysql_error(&my_connection)); 43 return-3; 44 } 45 } 46 mysql_free_result(res_ptr); 47 } 48 mysql_close(&my_connection); 49 printf("Connectionclosed.\n"); 379 50 } 51 else 52 { 53 fprintf(stderr,"Connectionfailed\n"); 54 if(mysql_errno(&my_connection)) 55 { 56 fprintf(stderr,"Connectionerror%d:%s\n", 57 mysql_errno(&my_connection),mysql_error(&my_connection)); 58 return-1; 59 } 60 } 61 return0; 62} 63 64voiddisplay_header() 65{ 66 MYSQL_FIELD*field_ptr; 67 printf("Columndetails:\n"); 68 while((field_ptr=mysql_fetch_field(res_ptr))!
=NULL) 69 { 70 printf("\tName:%s\n",field_ptr->name); 71 printf("\tType:"); 72 if(IS_NUM(field_ptr->type)) 73 { 74 printf("Numericfield\n"); 75 } 76 else 77 { 78 switch(field_ptr->type) 79 { 80 caseFIELD_TYPE_VAR_STRING: 81 printf("VARCHAR\n");break; 82 caseFIELD_TYPE_LONG: 83 printf("LONG\n");break; 84 default: 85 printf("Typeis%d,checkin.h\n",field_ptr->type); 86 } 87 } 88 printf("\tMaxwidth%d\n",field_ptr->length); 89 if(field_ptr->flags&AUTO_INCREMENT_FLAG) 90 printf("\tAutoincrements\n"); 91 printf("\n"); 92 } 380 数据库编程第9章 93} 94 95voiddisplay_row(MYSQL*ptr) 96{ 97 unsignedintfield_count; 98 field_count=0; 99 while(field_count 程序输出结果如下: $./ex7ConnectionessColumndetails: Name:childnoType:NumericfieldMaxwidth11Autoincrements Name:fnameType:VARCHARMaxwidth30 Name:ageType:NumericfieldMaxwidth11 Columndetails:1Jenny142John103Jack11Connectionclosed. 381 9.5小结 在这一章中,介绍了MySQL的用法以及用C语言访问MySQL数据库的方法,读者应该掌握数据库的基本概念,MySQL的安装和管理,MySQL相关的实用命令以及基于C的API的编程方法。
MySQL提供的API函数很多,限于篇幅,不在这里一一介绍,读者可以在MySQL的官方网站中找到相关的API介绍。
习题
一、填空题
1.数据库语言一般可分为以下两种:一种是______,它具有语法简明、可独立使用等特点;另一种则嵌入到某种程序设计语言中.如
C、FORTRAN、PASCAL、COBOL等,称为______。

2.一个典型的关系型数据库通常由一个或多个被称作______的对象组成。

3.在SQL命令中,______语句主要被用来对数据库进行查询并返回符合用户查询标准的结果数据;______语句被用来建立新的数据库表格;______语句向数据库表格中插入或添加新的数据行;______语句更新或修改满足规定条件的现有记录;______语句删除数据库表格中的行或记录;______语句删除某个表格以及该表格中的所有记录。

4.对于密码为1234的用户user1,为了用mysql开启选定的数据库db1,我们需要输入______。

5.在MySQL中,查看系统中当前存在的数据库命令是______,显示当前数据库中有哪些表的命令是______。

二、选择题
1.所有的SQL语句在结尾处都要使用______符号。
(A), (B): (C); (D).
2.当向数据库表格中添加新记录时,在关键词insertinto后面输入所要添加的______ 名称。
(A)数据库 (B)表格 (C)列 (D)值
3.______是MySQL自带的主要管理实用程序。
(A)mysqladmin(B)mysqldump(C)mysqlimport(D)mysqlshow4.在用C语言访问MySQL数据库的程序中,______函数成功返回一个指向MYSQL 382 数据库编程第9章 结构的指针。
(A)mysql_init(B)mysql_real_connect(C)mysql_options
5.从C向一个MySQL数据库的连接包括______步。
(A)1(B)2(C)3(D)
4 三、上机题 (D)mysql_error
1.在Linux系统上安装MySQL数据库,并为根用户设置密码,密码自定义。

2.在MySQL数据库中创建一个新数据库,并在数据库中创建一个数据库表student:该表表示一个学校的学生登记表,表的内容包含ID、学生姓名、年龄、入学日期、语文成绩、数学成绩、体育成绩、美术成绩。

3.编写一个C程序,访问上题中新建的数据库,并向数据库中添加几条记录。

4.编写一个C程序,访问上题中添加记录后的数据库,查询数据库中的内容,并用结构化方法输出查询内容。
383

标签: #c4d #转换成 #容量 #web #培训机构 #后缀名 #cs1.6怎么联机 #大众