第八章 MySQL

MySQL是一种关系型数据库管理系统(RDBMS,Relation Database Management System)。

MySQL是开源的。

虽然MySQL在许多场合下的使用是遵循GPL的,但是也有许多场合下必须购买它的商业许可证才能使用它。

MySQL读如"my sequel"。


安装

CentOS 7已经安装好了MySQL,如果没有安装,则使用下面命令安装:

$ yum install mariadb-server mariadb

启动的命令是:

$ systemctl start mariadb.service
$ mysql

其他安装方法见书本。

安装后的配置

安装完后,输入:

$ mysql -u root mysql

如果进入到MySQL控制台,就表示服务器正在运行。输入\s可得到更多关于服务器的信息。输入quit或\q退出控制台。

使用命令mysql -?可以获得更多有关服务器的信息,此命令的输出中,有一条Default options are read from the following files in the given order:,它告诉你在哪里可以找到配置文件,此配置文件用于配置MySQL服务器,通常是/etc/my.cnf

使用mysqladmin命令查看正在运行的服务器状态以及服务器的版本号:

$ mysqladmin -u root version

输出正在运行的服务器中所有的配置选项:

$ mysqladmin variables -u root

其中有几个特别有用的变量:

为了把InnoDB设置成默认存储引擎,需要修改MySQL服务器配置文件,在mysqld一节中添加:

default_storage_engine=InnoDB

更多信息可访问:MySQL官网

用户密码设置

MySQL的root用户和系统的root用户毫无关系。MySQL只不过默认使用一个称为"root"的用户作为管理用户。

一个最简单的设置密码的命令:

$ mysqladmin -u root password newpassword

或者:

$ mysql -u root
mysql> SET password=PASSWORD('newpassword');

如果想删除密码,则可以:

mysql> SET password=PASSWORD('');

一条SQL命令以分号结尾,严格来说,分号不属于SQL命令的一部分,它只是用来告诉MySQL客户端程序,一条SQL语句已经准备好被执行了。

SQL关键字不区分大小写,但使用大写可以便于阅读。

设置了密码的用户,必须提供密码参数才能登陆MySQL客户端程序:

$ mysql -u root -p

检查权限表确认密码设置

mysql> use mysql
mysql> SELECT user, host, password FROM user;

MySQL不仅能为用户保存不同的权限,也能为基于主机名的连接类保存不同的权限。

添加用户

以root用户身份连接到MySQL,然后使用grant命令来创建用户并赋予权限。

例子:

为ldw创建一个本地登录:

mysql> GRANT ALL ON *.* TO ldw@localhost IDENTIFIED BY '123456';
mysql> SELECT user, host, password FROM mysql.user;

IDENTIFIED BY是一个用于设定初始密码的语法。

*.*给予了用户非常广泛的权限。

安装后的故障修复

如果连接mysql失败,可使用ps命令检查服务器进程是否正在运行:ps aux | grep mysql

在CentOS 7上面,可以使用这个命令检查:systemctl status mariadb.service

其它的方法见书本。

MySQL管理

包含在MySQL发行版中的一些有用的工具程序使管理工作变得容易。

命令

除了mysqlshow命令外,所有的MySQL命令都接受如下3个标准参数:

命令选项 参数 说明
-u 用户名 指定一个用户名作为MySQL的用户名,默认情况下,mysql工具会尝试把当前的Linux用户名作为MySQL用户名
-p [密码] 如果给出了-p参数但是未提供密码,系统会提示输入密码。若没给-p参数,MySQL命令假设不需要密码
-h 主机名 用于连接位于不同主机上的服务器。对于本地服务器,总是可以省略

mysql命令

这是MySQL一个主要的且功能强大的命令行工具。

默认使用数据库foo来启动控制台(客户端)的命令如:

$ mysql -u ldw -p foo

通过非交互模式运行mysql:

$ mysql -u ldw --password=123456 foo < sqlcmd.sql

当mysql客户端连接到服务器后,除了标准的SQL92命令集以外,还有一些特定的命令被mysql支持。如:

命令 说明
help 显示命令列表
edit 编辑命令
exit或quit 退出MySQL客户端
go 执行命令
source <filename> 从指定文件执行SQL
status 显示服务器状态信息
system <command> 执行一个系统命令
tee <filename> 把所有输出的副本添加到指定文件中
use <database> 使用给定的数据库

MySQL最常使用的术语是database,它是一个基本独立的表格集。可以为每个数据库指定不同的用户,只要拥有适当的权限,就可以通过use命令在不同的数据库之间进行切换。

特定数据库mysql是由MySQL安装自动创建的,它用于保存如用户和权限这样的数据。

mysqladmin

快速进行MySQL数据库管理的主要工具。除了常见参数,还支持如下命令:

命令 说明
create <database_name> 创建一个新数据库
drop <database_name> 删除一个数据库
password <new_password> 修改密码
ping 检查服务器是否正在运行
reload 重载控制权限的grant表
status 提供服务器的状态
shutdown 停止服务器
variables 显示控制MySQL操作的变量及其当前值
version 提供服务器的版本号以及它持续运行的时间

如果不带参数调用mysqladmin命令,就可以从命令提示符下看到完整的选项列表。

mysqldump

mysqldump命令允许以SQL命令集的形式将部分或整个数据库导出到一个单独的文件中,该文件能被重新导入MySQL或其他的SQL RDBMS。

以下参数扩展了这个工具的功能:

命令 说明
-add-drop-table 添加SQL命令到输出文件,以在创建表的命令之前丢弃(删除)任何表
-e 使用扩展的insert语法
-t 只转储表中的数据,而不是用来创建表的信息
-d 只转储表结构,而不是实际数据

默认情况下,mysqldump将数据发送到标准输出,可以把它重定向到文件。

mysqldump命令对于迁移数据或快速备份非常有用。

一个转储数据库的例子:

$ mysqldump -u ldw -p table_name > table_name_bak.dump

mysqlimport

mysqlimport命令用于批量将数据导入到一个表中。

mysqlshow

这个小工具能够让你快速了解MySQL安装及其组成数据库的信息。

创建用户并赋予权限

MySQL管理员最常见的工作就是维护用户信息——在MySQL中添加和删除用户并管理他们的权限。

通过在MySQL控制台中使用grant和revoke命令来管理用户权限。

grant命令

MySQL的grant命令几乎完全遵循SQL92的语法。其常规格式是:

grant <privilege> on <object> to <user> [identified by user-password] [with grant option];

可以授予的特权值见书本。

授予特权的对象被标识为:database_name.table_name

在Linux传统中,*代表通配符,因此*.*代表每个数据库中的每个对象,foo.*代表数据库foo中的每个表。

如果指定的用户已经存在,他的特权会被编辑以反映所做的修改。如果用户不存在,他就会以指定的特权被创建。

在SQL语法中,特殊字符%代表通配符,它与shell环境中的*号的作用完全一致。任何时候使用%通配符都必须把它放到引号中,以与其他文本分开。

创建一个可以从任何主机进行连接的用户:

mysql> GRANT ALL ON foo.* TO ldw@'%' IDENTIFIED BY '123456';

revoke命令

管理员可以剥夺用户的权限。通过revoke命令:

revoke <a_privilege> on <an_object> from <a_user>

如:

mysql> REVOKE INSERT ON foo.* FROM rick@'%';

revoke命令不能删除用户,如果要完全删除一个用户,不要只是修改他们的权限,而应用revoke来删除他们的权限。然后,切换到mysql数据库,通过从user表中删除相应的行来完全删除一个用户:

mysql> use mysql
mysql> DELETE FROM USER WHERE user = "ldw";
mysql> FLUSH PRIVILEGES;

FLUSH PRIVILEGES告诉服务器,需要重载权限表。

密码

如果想为尚未拥有密码的用户指定密码,或者希望改变自己或别人的密码,你就需要以root用户身份连接到MySQL服务器,然后直接更新用户信息。例如:

mysql> use mysql
mysql> UPDATE user SET password = password('bar') WHERE user = 'ldw';
mysql> FLUSH PRIVILEGES;

创建数据库

创建一个数据库的命令可以是:

mysql> CREATE DATABASE test;

数据类型

MySQL的数据类型非常标准,书本里只做了简要的浏览,MySQL网站上的MySQL手册对此进行了更为详细的讨论。

见书本。

创建表

一个数据库表非常像电子表格,除了每行都必须包含相同数目和类型的列,而且每行必须以某种方式不同于表中的其他行。

创建数据库对象的完整SQL语法被称为DDL(data definition language, 数据库定义语言)。

见书本。

图形化工具

书中介绍了几个工具,不过我在工作中还未曾使用。

在工作中,我使用的是 Navicat (不过是破解版本),且运行于 Windows

在 CentOS 7 下,我下载了 mysql workbench 。

使用C语言访问MySQL数据库

可以使用许多不同的编程语言来访问MySQL,比如C, C++, PHP, Python。在此讨论C语言的接口。

连接例程

见connect1.c。

用C语言连接MySQL数据库包含两个步骤:

使用mysql_init来初始化连接句柄:

#include <mysql.h>
MYSQL *mysql_init(MYSQL *);

如果传递给NULL给此接口,它会返回一个指向新分配的连接句柄结构的指针。如果传递一个已有结构,它将被重新初始化。出错时返回NULL。

使用mysql_real_connect来向一个连接提供参数:

MYSQL *mysql_real_connect(MYSQL *connection,
    const char *server_host,
    const char *sql_user_name,
    const char *sql_password,
    const char *db_name,
    usigned int port_number,
    const char *unix_sock_name,
    unsigned int flags);

connection必须指向已经被mysql_init初始化过的结构。server_host是主机名(可以是IP地址,或者localhost)。sql_user_name和sql_password和字面含义一样。

port_number和unix_socket_name默认为0和NULL,表示采用MySQL的默认设置。

flag参数默认填0即可,对于介绍性的章节来说,没什么用。

使用完连接之后,通常在程序退出时,调用mysql_close关闭连接:

void mysql_close(MYSQL *connection);

如果connection是由mysql_init建立的,MYSQL结构会被释放,指针将会失效并无法再次使用。

mysql_options仅能在mysql_init和mysql_real_connect之间调用,可以设置一些选项。见书本。

错误处理

见connect2.c。

MySQL使用一系列由连接句柄结构报告的返回码。两个必备的例程是:

unsigned int mysql_errno(MYSQL *connection);
char *mysql_error(MYSQL *connection);

mysql_errno获得错误码,如果未设定错误,它将返回0。因为每次调用库都会更新错误码,所以只能得到最后一个执行命令的错误码,但上面两个例程是例外,它们不会导致错误码更新。

mysql_error获得文本错误信息,这些信息被写入一些内部静态内存空间中,如果想保存错误文本,需要把它复制到别的地方。

执行SQL语句

见insert1.c。

执行SQL语句的主要API函数为:

int mysql_query(MYSQL *connection, const char *query);

query是字符串形式的有效SQL语句(没有结束的分号)。如果成功,返回0。对于包含二进制数据的查询,可以使用mysql_real_query。

用于检测受影响的行数的函数:

my_ulonglong mysql_affected_rows(MYSQL *connection);

返回一个my_ulonglong类型是出于移植性的考虑,可以把它转换成无符号长整型。函数返回受之前的UPDATE, INSERT, DELETE查询影响的行数。

通常返回值0表示没有行受到影响,正数则是实际的结果,一般表示受语句影响的行数。如果是DELETE删除整个表的数据,由程序返回的结果是0。

发现插入的内容

见insert2.c。

如果一个列的类型是AUTO_INCREMENT,那么它会由MySQL自动分配ID。如何知道刚刚插入的记录的这个ID呢?

MySQL提供了LAST_INSERT_ID()函数,无论何时MySQL向AUTO_INCREMENT列中插入数据,MySQL都会基于每个用户对最后分配的值进行跟踪。用户可以这样发现该值:

mysql> SELECT LAST_INSERT_ID();

返回的数字在本次会话中是唯一的。

返回数据的语句

见select*.c。

数据是使用SELECT语句提取的。

在C应用程序中提取数据一般需要下面4个步骤:

使用完mysql_qurey发送SQL语句后,使用mysql_store_result或mysql_use_result来提取数据。接着使用一系列mysql_fetch_row调用来处理数据。最后使用mysql_free_result释放查询占用的内存资源。

一次提取所有数据的函数

可以使用mysql_store_result在一次调用中从SELECT中提取所有数据:

MYSQL_RES *mysql_store_result(MYSQL *connection);

需要在成功调用mysql_query之后使用此函数。这个函数将立刻保存在客户端中返回的所有数据。它返回一个指向结果集结构的指针,如果失败则返回NULL。

mysql_num_rows返回记录的数据,如果没有返回行,这个值将是0。

my_ulonglong mysql_num_rows(MYSQL_RES *result);

接下来,可以使用mysql_fetch_row来处理结果集,也可以使用mysql_data_seek, mysql_row_seek, mysql_row_tell在数据集中来回移动。

mysql_fetch_row: 这个函数从结果集中提取一行数据,并把它放到一个行结构中。当数据用完或发生错误时返回NULL。

MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);

在完成了对结果集的操作后,必须总是调用mysql_free_result函数来让MySQL库清理它分配的对象:

void mysql_free_result(MYSQL_RES *result);

一次提取一行数据

依靠mysql_use_result可以逐行提取数据:

MYSQL_RES *mysql_use_result(MYSQL *connection);

mysql_use_result在遇到错误时返回NULL。如果成功,返回指向结果集对象的指针。但是,它未将提取的数据放到它初始化的结果集中。

在之后使用mysql_fetch_row返回行结果必须通过网络。

处理返回的数据

MySQL返回两种类型的数据:

mysql_field_count函数返回结果集中的字段(列)数目:

unsigned int mysql_field_count(MYSQL *connection);

使用mysql_fetch_field函数可以将元数据和数据提取到一个新的结构中:

MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result);

此函数需要重复调用,直到返回表示数据结束的NULL值为止。MYSQL_FIELD包含了关于列的信息。见书本。

更多的函数

见书本。