【MySQL】第4期 用户管理与 C 语言连接编程详解

目录

开头

Ok了,今天这一期我们来一起学习MySQL的用户管理和如何用C语言对MySQL数据库的操作,废话不多说,我们直接开始

一.MySQL 用户管理

1.用户

MySQL 作为多用户数据库系统,默认的 root 账号拥有全局最高权限,若直接分配给所有使用者,会存在三大安全风险:

  • 数据泄露风险:任意用户可访问所有数据库的全部数据
  • 误操作风险:普通开发人员可删除库、修改系统配置
  • 权限失控风险:无法按业务做数据隔离(如业务 A 的人员只能访问业务 A 的库)

用户管理的核心目标是最小权限原则:为不同角色创建独立账号,仅分配其工作必需的权限,实现数据与操作的隔离

(1)用户信息存储位置

MySQL 的所有用户信息、权限信息都存储在系统数据库 mysql 的 user 表中,这是权限体系的核心存储

如上图,MySQL中的用户信息都是存放在mysql 数据库中的 user 表中

三个核心字段含义:

  • user:用户名,仅用于身份标识
  • host :允许该用户登录的主机地址,是安全控制的核心
    • localhost:仅允许从数据库本机登录
    • 192.168.1.%:允许该网段的主机登录
    • %:允许从任意主机登录(生产环境强烈不推荐)
  • authentication_string :经 MySQL 密码算法加密后的密码密文,5.7 版本后替代了旧版的 password 字段

(2)用户的唯一标识

MySQL 中用户不是仅由用户名唯一确定,而是由「用户名 + host 主机地址」共同唯一标识 。

例如:

  • 'zhangsan'@'localhost' 和 'zhangsan'@'192.168.1.100' 是两个完全独立的用户,密码、权限均可不同

(3)用户的基础操作

a.创建用户

语法格式:

复制代码
create user '用户名'@'登陆主机/IP' identified by '密码';

示例 :创建一个只能本地登录的用户 yht,密码为 12345678

复制代码
create user 'yht'@'localhost' identified by '12345678';

关键注意事项:

  1. 主机范围控制 :不要轻易创建 'user'@'%' 这类允许任意地址登录的账号,会极大增加被暴力破解的风险。
  2. 密码策略限制 :MySQL 默认开启密码强度校验插件,简单密码会触发 ERROR 1819 报错。
    • 查看密码策略:SHOW VARIABLES LIKE 'validate_password%';
    • 可根据场景调整策略等级、密码长度等参数,或使用符合复杂度要求的密码

b.删除用户

语法格式:

复制代码
drop user '用户名'@'主机名';

c.修改用户密码

分为两种场景,对应不同语法:

  1. 普通用户修改自己的密码

    set password = password('新密码');

  2. root 用户修改指定用户的密码

    set password for '用户名'@'主机名' = password('新密码');

其中 password() 是 MySQL 内置的密码哈希函数,会将明文密码加密为密文存储

2.权限管理机制

(1)权限体系概述

MySQL 权限按作用范围 从大到小可分为:全局层级 > 数据库层级 > 表层级 > 列层级 > 子程序层级。

按权限类型可分为数据操作、结构操作、管理操作三大类,核心权限如下:

表格

权限分类 具体权限 作用范围
数据操作 SELECT、INSERT、UPDATE、DELETE 表 / 列
结构操作 CREATE、DROP、ALTER、INDEX 库 / 表
视图 / 存储过程 CREATE VIEW、EXECUTE、CREATE ROUTINE 视图 / 子程序
系统管理 CREATE USER、SUPER、SHOW DATABASES、FILE 全局

(2)相关操作

a.赋权:grant

语法格式:

复制代码
grant 权限列表 on 库.对象名 to '用户名'@'登陆位置' [identified by '密码'];

语法说明:

  • 权限列表:多个权限用逗号分隔,all [privileges] 代表授予该范围下的所有权限
  • 对象范围:
    • *.*:全局范围,所有数据库的所有对象
    • 库名.*:指定数据库下的所有表、视图等对象
    • 库名.表名:指定数据库下的某一张表
  • identified by:可选子句,用户已存在则同步修改密码,用户不存在则隐式创建用户(不推荐)

b.查看用户权限
复制代码
show grants for 'whb'@'localhost';

c.权限回收:revoke

语法格式:

复制代码
revoke 权限列表 on 库.对象名 from '用户名'@'登陆位置';

d.权限生效
  • 通过 grant / revoke 操作的权限,MySQL 会自动刷新权限缓存,立即生效。

  • 若手动修改 mysql.user 等系统表来变更权限,需要执行以下命令手动刷新才能生效:

    flush privileges;

二.C 语言连接 MySQL:Connector/C

Connector/C(也常称为 libmysqlclient)是 MySQL 官方提供的 C 语言编程接口,它封装了 MySQL 客户端 / 服务器的 TCP 通信协议与 SQL 交互逻辑,让 C/C++ 程序无需手动处理网络包、协议解析,只需通过函数调用即可完成数据库的全部操作。

核心交互模型

C 程序与 MySQL 的交互本质是「客户端 - 服务器」模型:

  1. C 程序作为客户端,通过 Connector/C 库向 MySQL 服务端发送 SQL 请求
  2. MySQL 服务端执行 SQL,将结果通过网络返回给客户端
  3. Connector/C 库解析返回的数据包,转换成 C 语言可读取的结构体与数据

1.开发环境搭建

(1) Connector/C 库的目录结构

下载后的开发包分为两大核心目录,分别对应编译期和运行期:

目录 作用 核心内容
include/ 编译期:提供函数声明与结构体定义 核心头文件 mysql.h,以及辅助头文件:错误码定义、网络通信、内存管理、协议解析、字符集处理等
lib/ 运行期:提供功能的二进制实现 静态库 libmysqlclient.a:编译时直接打包进可执行文件动态库 libmysqlclient.so(Linux):运行时动态加载,体积更小

(2)编译与运行

先写最简代码验证库是否能正常引入:

2.核心操作流程

C 语言操作 MySQL 遵循严格的线性流程:初始化句柄 → 建立连接 → 执行 SQL → 读取结果 → 释放资源 → 关闭连接

a.第一步:初始化连接句柄 mysql_init

函数原型

复制代码
MYSQL *mysql_init(MYSQL *mysql);

作用

分配并初始化一个 MYSQL 结构体对象,它是所有数据库操作的核心上下文句柄,后续所有 API 都需要传入这个对象。

底层细节

MYSQL 结构体内部存储了:

  • 连接基本信息:主机地址、端口、用户名、默认数据库、字符集
  • 网络状态:套接字描述符、收发缓冲区
  • 函数指针表 st_mysql_methods:封装了读行、写包、协议解析等底层操作,后续的查询、读结果都会调用这里的函数指针

参数与返回值

  • 传 NULL:库内部自动申请内存,创建并返回新的 MYSQL 对象
  • 传已有的 MYSQL 地址:重新初始化该对象
  • 返回值:成功返回有效指针,失败返回 NULL

b.第二步:建立数据库连接 mysql_real_connect

函数原型

复制代码
MYSQL *mysql_real_connect(
    MYSQL *mysql,        // 初始化好的连接句柄
    const char *host,    // 数据库主机地址
    const char *user,    // 数据库用户名
    const char *passwd,  // 数据库密码
    const char *db,      // 默认连接的数据库,可传NULL
    unsigned int port,   // 数据库端口,默认3306
    const char *unix_socket, // Unix套接字路径,一般传NULL
    unsigned long clientflag // 客户端标志位,一般传0
);

底层执行流程

这个函数会完成完整的 MySQL 连接握手:

  1. 建立 TCP 网络连接(如果 host 是 IP)或 Unix 套接字连接(如果是 localhost)
  2. 与 MySQL 服务端协商协议版本、字符集
  3. 发送用户名、加密后的密码进行身份认证
  4. 建立会话,绑定默认数据库

参数说明

  • host:填 localhost 默认走 Unix 套接字(性能更高),填 IP 地址走 TCP 协议
  • db:可以传 NULL,连接后再通过 SQL 语句 use 库名 切换数据库
  • clientflag:常用标志如 CLIENT_MULTI_STATEMENTS 支持一次执行多条 SQL,普通场景传 0 即可

中文乱码的解决方案

MySQL 连接默认字符集是 latin1,读取中文会出现乱码。连接成功后必须立即设置字符集:

复制代码
mysql_set_character_set(conn, "utf8");

原理:保证「客户端连接字符集」和「数据库字符集」一致,避免字符转码错误。

返回值与错误处理

  • 成功:返回传入的 MYSQL 句柄
  • 失败:返回 NULL,可通过 mysql_error(conn) 获取错误信息

c.第三步:执行 SQL 语句 mysql_query

函数原型

复制代码
int mysql_query(MYSQL *mysql, const char *sql);

作用

将 SQL 语句发送给 MySQL 服务端执行,支持 SELECT、INSERT、UPDATE、DELETE 等所有类型的 SQL

参数与返回值

  • sql:要执行的 SQL 字符串,必须以 \0 结尾,末尾不需要加分号
  • 返回值:0 代表执行成功,非 0 代表执行失败

分类说明

  1. 非查询类 SQL(INSERT/UPDATE/DELETE) :执行成功后,可通过 mysql_affected_rows(conn) 获取受影响的行数。
  2. 查询类 SQL(SELECT):执行成功只是代表服务端准备好结果了,数据还在服务端缓冲区,需要主动拉取到本地

d.第四步:获取查询结果集 mysql_store_result

函数原型

复制代码
MYSQL_RES *mysql_store_result(MYSQL *mysql);

作用

一次性从服务端读取全部查询结果 ,缓存到本地内存中,返回一个 MYSQL_RES 结果集对象

内存泄漏风险 :该函数会自动 malloc 内存存储结果,使用完必须调用 mysql_free_result() 释放,否则会造成严重的内存泄漏。

返回值

成功返回 MYSQL_RES 结果集指针,失败返回 NULL


e.第五步:读取结果集数据

拿到结果集后,可以通过一组 API 获取元信息和逐行数据

  1. 获取结果集元信息
函数 作用 返回值
mysql_num_rows(res) 获取结果的总行数 my_ulonglong(无符号长整型)
mysql_num_fields(res) 获取结果的总列数 unsigned int
mysql_fetch_fields(res) 获取所有列的字段信息 MYSQL_FIELD* 数组,每个元素包含列名、字段类型、长度等

示例:获取并打印所有列名

  1. 逐行读取数据 mysql_fetch_row

函数原型

复制代码
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);

核心说明

  • MYSQL_ROW 本质是 char ** 类型,也就是字符串数组,每个元素对应一行中的一列数据。
  • 所有数据都以字符串形式返回,哪怕是数字类型,也会被转成字符串,需要自己做类型转换。
  • 内部有行指针,每调用一次自动向后移动一行;读取完所有行后返回 NULL。
  • 如果某字段值为 NULL,对应的数组元素是 NULL,必须做空判断,否则会触发段错误

f.第六步:释放资源与关闭连接
  1. 释放结果集:查询操作结束后,必须释放结果集内存

    mysql_free_result(res);

  2. 关闭数据库连接:程序退出前关闭连接,释放网络与句柄资源

    mysql_close(conn);


g.事务控制 API

Connector/C 原生支持数据库事务控制,核心三个函数(仅 InnoDB 等支持事务的引擎有效):

函数 作用 参数说明
mysql_autocommit(my, mode) 设置自动提交模式 mode=1 开启自动提交(MySQL 默认);mode=0 关闭自动提交,开启手动事务
mysql_commit(my) 提交事务 将当前事务的所有修改持久化到数据库
mysql_rollback(my) 回滚事务 撤销当前事务所有未提交的修改

结尾

这一期对于MySQL的学习就到这里了,希望对你的学习有所帮助。感谢你的点赞、关注。我主页里有更好康的呦!

往期回顾

  1. 【MySQL】第3期 索引、事务与视图系统详解
  2. 【MySQL】 第2期 查询与函数系统详解:从基础 CRUD 到复合多表查询
  3. 【MySQL】 第1期 从核心概念到表约束全解析
相关推荐
刚入门的大一新生2 小时前
Linux-进程间通信1
linux·运维·服务器
郭萌6962 小时前
多商户平台的分销佣金:为什么同一笔订单,换个时间跑会算出另一个人
mysql·php
张宇Joaquin2 小时前
Linux系统下磁盘扇区512n、512e和4kn的区别
linux·运维·数据库
道虽迩,不行不至2 小时前
数据库自动连库执行增量脚本-Linux
linux·数据库
GeW2 小时前
新质生产力发展路线图来了,Linux和数据库人该怎么接
linux·数据库
西索斯coding2 小时前
Grok 4.7 调用一直 401 怎么办?不是 Key 过期,是 Authorization 头格式问题——排查全流程 + 修复示例
服务器·开发语言·ai·php
yunwei372 小时前
eBPF 示例:使用 CUPTI 构建 GPU 火焰图分析器
linux·后端·性能优化
库库的数据库笔记3 小时前
金融核心交易系统的数据库国产信创改造该如何做?
大数据·数据库·分布式·mysql·oracle·金融·数据库架构
Linux实战笔记3 小时前
MySQL 索引失效的三种典型场景与 EXPLAIN 分析
mysql·索引失效·explain·执行计划·sql 调优