产品网站更新内容,wordpress文章支持多形式,wordpress 数据库,国外企业网络Linux下MySQL的简单使用
导语MySQL安装与配置 MySQL安装密码设置 MySQL管理 命令 myisamchkmysql其他 常见操作 C语言访问MYSQL 连接例程错误处理使用SQL 总结参考文献
导语
这一章是MySQL的使用#xff0c;一些常用的MySQL语句属于本科阶段内容#xff0c;然后是C语言和M…Linux下MySQL的简单使用
导语MySQL安装与配置 MySQL安装密码设置 MySQL管理 命令 myisamchkmysql其他 常见操作 C语言访问MYSQL 连接例程错误处理使用SQL 总结参考文献
导语
这一章是MySQL的使用一些常用的MySQL语句属于本科阶段内容然后是C语言和MySQl之间的交互可以看到C语言已经有成熟的和MySQL的接口
MySQL安装与配置
MySQL安装
MySQL的安装很简单只需要执行几个shell命令就行需要注意的是对于Ubuntu新机器来说最好不要一开始就执行sudo apt update因为很多包之间的依赖是复杂且未知的如果直接全部更新可能会导致在跟书上同步实验时出问题命令参考了ubuntu 23.10.1 mysql 安装
sudo apt install mysql-server -y#这里就安装好了服务器
systemctl start mysql#开启mysql服务
systemctl status mysql#检查状态如果出现mysql就没问题sudo mysul -u root mysql#进入mysql
ps -el | grep mysqld#可以看mysql是否启动下面这个是备选方案是在新机器上装的
sudo apt-get update
sudo apt-get install libmysqlclient-dev
mysql_config --cflags
mysql_config --libs后两条命令是检测MySQL Connector/C是否安装完成由于新版本的MySQL已经不支持书上的写法所以需要安装这个包正常应该显示如下图 之后直接安装服务器即可
sudo apt-get update
sudo apt-get install mysql-server通过下面的程序验证安装是否成功
#include stdio.h
#include mysql/mysql.hint main() {MYSQL *conn;conn mysql_init(NULL);if (conn NULL) {fprintf(stderr, mysql_init() failed
);return EXIT_FAILURE;}if (mysql_real_connect(conn, localhost, user, password, database, 0, NULL, 0) NULL) {fprintf(stderr, mysql_real_connect() failed: %s
, mysql_error(conn));mysql_close(conn);return EXIT_FAILURE;}printf(Connected to the database successfully!
);mysql_close(conn);return EXIT_SUCCESS;
}执行的命令和结果如下
gcc -o test_program test_program.c $(mysql_config --cflags) $(mysql_config --libs)密码设置
一开始的root是没有密码的可以通过命令查看各用户的密码如下可以看到root密码为空 这里需要注意的是新版的MySQL和老版的不一样新版本的password列改成了authentication_string
可以执行命令来设置密码修改后查看可以看到root有密码但是被MySQL加密过了再次登录时直接回车发现无法识别只有输入密码才能识别用户 这里我们删除除去root之外的默认用户并且删除从localhost以外任何主机的登录 到此为止我们有了一个运行的MySQL该MySQL只有设定密码的root通过本地才能连接为了方便后续的操作这里创建一个普通用户rick它将能用三种方法来连接MySQL本地连接从IP连接从wiley.com域中任何机器连接
首先为rick创建一个本地登录这里书上给的代码太老了已经不适配现在的MySQL更改成了现在版本的最新的 MySQL 版本中GRANT 语句不再用于设置用户密码。密码应该通过单独的 CREATE USER 或 SET PASSWORD 语句来设置。 通过三种不同的方式设置了三个用户可以通过select命令展示可以看到三种方式都成功了并且rick的权利很大 MySQL管理
命令
所有命令都接受三个标准参数
-u 用于指定用户用户名 -p 用于提示密码如果在命令行中未直接提供 -h 用于指定主机MySQL 服务器地址
除了标准参数之外每个命令还有自己的命令选项
myisamchk
通常情况下myisamchk以创建的mysql用户运行并且工作目录为数据表在的目录中常见的命令选项有
-c 检查表以发现错误 -e 执行扩展检查 -r 修复发现的错误
mysql
使用mysql可以不经过MySQL的控制台完成很多功能通过在命令行最后添加数据库名称作为参数即可可以通过 mysql --help | less来查看所有的命令行选项列表
其他
还有一些其他的命令如mysqladmin、mysqlbug等由于MySQL已经相对于书上更新很多了所以很多命令已经过时在此不多赘述
常见操作
书上提供的常见操作包括grant、revoke以及数据类型等这些属于本科阶段SQL的基本内容在此不再赘述跳过
C语言访问MYSQL
连接例程
C语言连接MySQL需要先初始化一个连接句柄结构然后再进行实际的连接句柄通过mysql_init函数初始化函数原型具体如下mysql_init() 函数通常是在使用 MySQL 客户端 API 进行数据库编程时的第一个步骤。它为连接操作做了准备确保在进行连接操作之前连接对象处于一个已初始化的状态
MYSQL *mysql_init(MYSQL *);
//mysql一个指向 MYSQL 结构体的指针。如果该指针为空
//mysql_init() 将分配一个新的 MYSQL 结构体并返回它。如果提供了一个非空指针它会用新的数据初始化该对象真正与数据库进行连接的是mysql_real_connect函数函数原型如下
MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *dbname, unsigned int port, const char *unix_socket, unsigned long client_flag);
//mysql是初始化之后的句柄还有例程函数和关闭函数在此不赘述
现在尝试创立一个数据库向其中填入数据并通过C语言访问它 逐行输入对数据库的操作比较麻烦并且容易出错可以把要执行的命令单独做成文件然后直接导入执行
-- Create the table childrenCREATE TABLE children (childno int(11) NOT NULL auto_increment,fname varchar(30),age int(11),PRIMARY KEY (childno)
);-- Populate the table childrenINSERT INTO children (childno, fname, age) VALUES (1, Jenny, 21);
INSERT INTO children (childno, fname, age) VALUES (2, Andrew, 17);
INSERT INTO children (childno, fname, age) VALUES (3, Gavin, 8);
INSERT INTO children (childno, fname, age) VALUES (4, Duncan, 6);
INSERT INTO children (childno, fname, age) VALUES (5, Emma, 4);
INSERT INTO children (childno, fname, age) VALUES (6, Alex, 15);
INSERT INTO children (childno, fname, age) VALUES (7, Adrian, 9);可以看到数据都被成功插入了
之后可以通过上述函数来连接数据库由于系统和包之间的依赖问题以及mysql的版本问题导致这个程序无法在旧机上运行暂时没有找到解决方案在新机上可以运行运行结果和程序如下
#include stdlib.h
#include stdio.h
#include mysql/mysql.h // 包含新版 MySQL Connector/C 的头文件int main(int argc, char *argv[])
{MYSQL *con;// 初始化 MySQL 连接句柄con mysql_init(NULL);if (con NULL) {fprintf(stderr, mysql_init() failed
);return EXIT_FAILURE;}// 连接数据库if (mysql_real_connect(con, localhost, rick, 111111, foo, 0, NULL, 0) NULL) {fprintf(stderr, mysql_real_connect() failed
);fprintf(stderr, Error: %s
, mysql_error(con));mysql_close(con);return EXIT_FAILURE;}// 输出连接成功状态printf(Connected successfully!
);// 关闭连接mysql_close(con);return EXIT_SUCCESS;
}执行的时候需要添加对应的inlcude路径和库文件路径
错误处理
MySQL使用一系列由连接句柄结构报告的返回码来获取错误信息具体的函数原型如下
unsigned int mysql_errno(MYSQL *connection);
//返回错误码
char *mysql_error(MYSQL *connection);
//返回有意义的文本信息这里是书上给出的一个例子以及运行结果可以看到屏幕上输出了错误信息
#include stdio.h
#include stdlib.h
#include mysql.hint main(int argc, char *argv[]) {MYSQL my_connection;mysql_init(my_connection);if (mysql_real_connect(my_connection, localhost, rick, I do not know, foo, 0, NULL, 0)) {printf(Connection success
);mysql_close(my_connection);} else {fprintf(stderr, Connection failed
);if (mysql_errno(my_connection)) {fprintf(stderr, Connection error %d: %s
,mysql_errno(my_connection), mysql_error(my_connection));}}return EXIT_SUCCESS;
}使用SQL
这里直接给出一些C语言执行SQL语句的函数原型和简单解释
int mysql_query(MYSQL *connection, const char *query);
//第一个是初始化后的句柄第二个是sql语句返回错误码
my_ulonglong mysql_affected_rows(MYSQL *connection);
//查询上一条指令运行后影响了多少行书上给出了一个使用AUTO_INCREMENT的代码实例下面是修改后的程序和运行结果AUTO_INCREMENT对每次插入的数据分配一个新的id值并进行追踪
#include stdio.h
#include stdlib.h
#include mysql.h#define DB_HOST localhost
#define DB_USER rick // 用户名 rick
#define DB_PASS 111111 // 数据库密码
#define DB_NAME foo // 数据库名称 foo// 错误处理函数减少冗余代码
void handle_error(MYSQL *connection, const char *message) {fprintf(stderr, %s
Error %d: %s
, message, mysql_errno(connection), mysql_error(connection));mysql_close(connection);exit(EXIT_FAILURE);
}int main(int argc, char *argv[]) {MYSQL my_connection;MYSQL_RES *res_ptr;MYSQL_ROW sqlrow;int res;// 初始化 MySQL 连接对象mysql_init(my_connection);// 连接数据库if (!mysql_real_connect(my_connection, DB_HOST, DB_USER, DB_PASS, DB_NAME, 0, NULL, 0)) {handle_error(my_connection, Connection failed);}printf(Connection success
);// 插入数据到表中res mysql_query(my_connection, INSERT INTO children(fname, age) VALUES(Robert, 7));if (res) {handle_error(my_connection, Insert error);} else {printf(Inserted %lu rows
, (unsigned long)mysql_affected_rows(my_connection));}// 查询最后插入的数据res mysql_query(my_connection, SELECT LAST_INSERT_ID());if (res) {handle_error(my_connection, SELECT error);}// 获取查询结果res_ptr mysql_use_result(my_connection);if (res_ptr) {// 迭代结果集并输出while ((sqlrow mysql_fetch_row(res_ptr))) {printf(We inserted childno %s
, sqlrow[0]);}// 释放结果集mysql_free_result(res_ptr);} else {fprintf(stderr, Failed to retrieve result set.
);}// 关闭连接mysql_close(my_connection);return EXIT_SUCCESS;
}可以看到成功插入了一行并且通过LAST_INSERT_ID拿到了ID 这里附上书上数据对应的插入代码
-- Create the table childrenCREATE TABLE children (childno INT(11) AUTO_INCREMENT NOT NULL PRIMARY KEY,fname VARCHAR(30),age INT
);-- Populate the table childrenINSERT INTO children (fname, age) VALUES (Jenny, 21);
INSERT INTO children (fname, age) VALUES (Andrew, 17);
INSERT INTO children (fname, age) VALUES (Gavin, 8);
INSERT INTO children (fname, age) VALUES (Duncan, 6);
INSERT INTO children (fname, age) VALUES (Emma, 4);
INSERT INTO children (fname, age) VALUES (Alex, 15);
INSERT INTO children (fname, age) VALUES (Adrian, 9);
INSERT INTO children (fname, age) VALUES (Ann, 3);
INSERT INTO children (fname, age) VALUES (Ann, 4);
INSERT INTO children (fname, age) VALUES (Ann, 3);
INSERT INTO children (fname, age) VALUES (Ann, 4);除了上述两个基本的函数之外还有一些其他的函数函数原型如下
MYSQL_RES *mysql_store_result(MYSQL *connection);
//从返回数据的语句中提取所有的数据返回一个指向结果集的指针
my_ulonglong mysql_num_rows(MYSQL_RES *result);
//统计返回结果中的行数
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
//从结果集中提取一行把这一行放在行机构里每次使用一个
void mysql_data_seek(MYSQL_RES *result, my_ulonglong offset);
//在结果集中跳转第二个参数是行号设置下一个被fetch操作返回的行
MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES *result);
//返回一个偏移值表示结果集中的当前位置不是行号
void mysql_free_result(MYSQL_RES *result);
//对结果集的操作完成后需要调用这个函数清理已经分配的对象
MYSQL_RES *mysql_use_result(MYSQL *connection);
//提取一行数据返回指向对象的指针不会缓存
//适合处理大数据量的查询结果因为它允许逐行读取而不会将所有行一次性加载到内存中这样可以有效减少内存的使用
unsigned int mysql_field_count(MYSQL *connection);
//获取最近一次查询的结果集中字段列的数量
MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result);
//用于从查询结果的字段列表中获取每个字段的描述信息类似于字段的元数据。
//返回一个指向 MYSQL_FIELD 结构体的指针这个结构体包含了字段的详细信息例如字段名、类型等。下面是书上给出的一个综合程序用chatgpt优化了基本上用到了上面的所有函数还有运行结果和具体的程序解释
#include stdlib.h
#include stdio.h
#include mysql.h// MySQL 连接对象和结果集
MYSQL my_connection;
MYSQL_RES *res_ptr;
MYSQL_ROW sqlrow;// 函数声明
void display_header();
void display_row();int main(int argc, char *argv[]) {int res;int first_row 1; // 用于确保我们只显示一次表头// 初始化 MySQL 连接对象mysql_init(my_connection);// 尝试连接到数据库if (mysql_real_connect(my_connection, localhost, rick, 111111, foo, 0, NULL, 0)) {printf(Connection success
);// 执行 SQL 查询选择年龄大于 5 的记录res mysql_query(my_connection, SELECT childno, fname, age FROM children WHERE age 5);if (res) {// 查询执行失败打印错误信息fprintf(stderr, SELECT error: %s
, mysql_error(my_connection));} else {// 使用 mysql_store_result() 获取结果集到内存res_ptr mysql_store_result(my_connection);if (res_ptr) {// 获取每行的数据并显示while ((sqlrow mysql_fetch_row(res_ptr))) {if (first_row) {// 首次显示表头display_header();first_row 0;}// 显示每行数据display_row();}// 释放结果集资源mysql_free_result(res_ptr);} else {// 获取结果集失败打印错误信息fprintf(stderr, Failed to retrieve result set: %s
, mysql_error(my_connection));}}// 关闭数据库连接mysql_close(my_connection);} else {// 连接失败打印错误信息fprintf(stderr, Connection failed
);if (mysql_errno(my_connection)) {fprintf(stderr, Connection error %d: %s
,mysql_errno(my_connection), mysql_error(my_connection));}}return EXIT_SUCCESS;
}// 显示表头列出字段名称及其相关属性
void display_header() {MYSQL_FIELD *field_ptr;//获得列名printf(Column details:
);while ((field_ptr mysql_fetch_field(res_ptr)) ! NULL) {// 显示字段的名称printf( Name: %s
, field_ptr-name);printf( Type: );// 判断字段类型并显示if (IS_NUM(field_ptr-type)) {//数字printf(Numeric field
);} else {switch (field_ptr-type) {//字符串case FIELD_TYPE_VAR_STRING:printf(VARCHAR
);break;case FIELD_TYPE_LONG:printf(LONG
);break;default:printf(Type is %d, check in mysql_com.h
, field_ptr-type);}}// 显示字段的最大长度printf( Max width %ld
, field_ptr-length);// 检查字段是否具有 AUTO_INCREMENT 属性if (field_ptr-flags AUTO_INCREMENT_FLAG) {printf( Auto increments
);}printf(
);}
}// 显示查询结果的每一行
void display_row() {unsigned int field_count;// 遍历每一列打印其值field_count 0;while (field_count mysql_num_fields(res_ptr)) {//如果域名数量比当前索引大if (sqlrow[field_count]) {//sqlrow存了这一行的数据printf(%s , sqlrow[field_count]);} else {printf(NULL );}field_count;}printf(
);
}还有更多的函数在此不再赘述可以查看MYSQL手册相关
总结
可以看到C语言已经有了很成熟的与MySQL交互的接口并且大部分函数的使用是和MySQL版本不相关的但实际在Ubuntu运行的时候还是需要注意MySQL的版本和包的问题因为新版本的MySQL库修改了一些配置文件的位置和相关的依赖包
参考文献
ubuntu 23.10.1 mysql 安装ChatGPT