【MySQL】视图、用户管理、MySQL使用C\C++连接
📚 博主的专栏
🐧 Linux | 🖥️ C++ | 📊 数据结构 | 💡C++ 算法 | 🅒 C 语言 | 🌐 计算机网络 |🗃️ mysql
摘要:本文介绍了MySQL视图和用户管理的核心知识点。在视图部分,说明了视图的创建、修改、删除操作及其与基表的关联性,强调视图作为虚拟表的特点和使用限制。用户管理部分详细讲解了用户创建、权限分配、密码修改等操作,包括GRANT/REVOKE命令的使用及安全注意事项。此外,还涵盖了使用C语言API连接MySQL数据库的基本流程,包括初始化连接、执行查询、处理结果集等关键操作。文章最后简要提及了高级功能如预处理语句和事务处理,为数据库开发提供了全面指导。
目录
视图
基本使用
视图规则和限制
MySQL用户管理
用户管理
用户管理基础
查看用户信息
创建用户
删除用户
修改用户密码
数据库权限管理
授予权限
回收权限
关键注意事项
操作示例场景
MySQL访问(C\C++)
准备工作,建立新数据库用户、安装好库以及头文件
更好的安装办法:
引入库:
mysql接口介绍
mysql常用接口C语言
连接管理
mysql_init初始化Mysql对象
mysql_real_connect链接数据库
查询执行
mysql_query下发mysql命令
mysql_store_result获取执行结果
结果处理
mysql_num_rows获取结果行数
mysql_num_fields获取结果列数
mysql_fetch_row获取结果内容
mysql_fetch_fields获取列名
关闭链接
mysql_close 关闭mysql链接
错误处理
mysql_error获取最近一次的错误信息
mysql_errno获得最近一次操作的错误代码
常用接口完整使用示例
高级功能接口
预处理语句
事务处理
注意事项
Mysql的第3种连接方式图形化界面:
视图
视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。视图的数据变化会影响到基表,基表的数据变化也会影响到视图
基本使用
在之前学习表的内连接的时候,我们通过这样的方式将两个表联系在一起。
接下来我们看使用视图的区别:
创建视图
create view 视图名 as select语句;
案例
create view v_ename_dname as select ename, dname from EMP, DEPT where EMP.deptno=DEPT.deptno;
在内存级别上,视图就是表,将我们刚刚查到的内容数据,放在临时表结构当中。
修改了视图,对基表数据有影响
修改了基表,对视图有影响
原来的deptno=30的位置并不是aaaaa
删除视图
drop view 视图名;
视图规则和限制
- 与表一样,必须唯一命名(不能出现同名视图或表名)
- 创建视图数目无限制,但要考虑复杂查询创建为视图之后的性能影响
- 视图不能添加索引,也不能有关联的触发器或者默认值
- 视图可以提高安全性,必须具有足够的访问权限
- order by 可以用在视图中,但是如果从该视图检索数据 select 中也含有 order by ,那么该视图中的 order by 将被覆盖
- 视图可以和表一起使用
MySQL用户管理
用户管理
用户管理基础
查看用户信息
查看所有用户及登录主机:
SELECT user, host FROM mysql.user;
创建用户
基本语法:
CREATE USER '用户名'@'主机' IDENTIFIED BY '密码';
示例(本地访问用户):
CREATE USER 'dev_user'@'localhost' IDENTIFIED BY 'StrongPassword!123';
注意事项:
主机限制:
localhost
:仅允许本地连接。
%
:允许所有远程IP连接(需谨慎使用)。指定具体IP(如
192.168.1.100
)。认证插件:
MySQL 8.0默认使用caching_sha2_password
。若需兼容旧客户端(如PHP 7.x),可改用旧插件:远端登录(例如在Windows上访问我云服务器上的Linux上的mysql):但是我们非常不建议将mysql对应的端口号暴露在公网上。CREATE USER 'legacy_user'@'%' IDENTIFIED WITH mysql_native_password BY 'password';
删除用户
删除指定用户:
DROP USER '用户名'@'主机';
示例:
DROP USER 'dev_user'@'localhost';
修改用户密码
修改密码命令:
ALTER USER '用户名'@'主机' IDENTIFIED BY '新密码';
或者使用set,来设置,无论是创建好用户还是设置密码,更改密码,用户级操作都可以使用flush privileges来刷新
示例:
ALTER USER 'dev_user'@'localhost' IDENTIFIED BY 'NewPassword456!';
数据库权限管理
授予权限
基本语法:
GRANT 权限 ON 数据库.表 TO '用户名'@'主机';
常用权限:
SELECT
(查询)、INSERT
(插入)、UPDATE
(更新)、DELETE
(删除)
CREATE
(创建表)、DROP
(删除表)、ALL PRIVILEGES
(所有权限)示例1(授予某数据库全部权限):
GRANT ALL PRIVILEGES ON production_db.* TO 'dev_user'@'localhost';
示例2(授予特定表只读权限):
GRANT SELECT ON sales_db.reports TO 'analyst'@'%';
生效说明:
使用
GRANT
命令后权限自动生效,无需额外操作。若直接修改权限表(如
mysql.user
),需执行FLUSH PRIVILEGES;
。回收权限
回收权限语法:
REVOKE 权限 ON 数据库.表 FROM '用户名'@'主机';
示例(回收删除权限):
REVOKE DELETE ON production_db.* FROM 'dev_user'@'localhost';
查看用户权限:
SHOW GRANTS FOR 'dev_user'@'localhost';
关键注意事项
最小权限原则:
避免使用ALL PRIVILEGES
或%
主机,按需分配权限以降低安全风险。认证插件兼容性:
若客户端不支持caching_sha2_password
,需显式指定mysql_native_password
。权限生效机制:
GRANT
/REVOKE
命令自动生效。手动修改权限表后需执行
FLUSH PRIVILEGES;
。登录MySQL命令行:
sudo mysql -u root -p # 使用sudo可跳过密码(若已配置免密登录)
操作示例场景
场景1:创建只读用户
CREATE USER 'readonly'@'192.168.1.5' IDENTIFIED BY 'ReadOnlyPass!'; GRANT SELECT ON inventory.* TO 'readonly'@'192.168.1.5';
场景2:限制用户操作范围
CREATE USER 'webapp'@'%' IDENTIFIED BY 'WebAppPass123'; GRANT SELECT, INSERT, UPDATE ON web_db.* TO 'webapp'@'%'; REVOKE DROP ON web_db.* FROM 'webapp'@'%'; # 禁止删除表
MySQL访问(C\C++)
在正常使用的时候,一定是程序区访问数据库。
准备工作,建立新数据库用户、安装好库以及头文件
1、建立新数据库用户
新建立一个用户connector:
create user 'connector'@'localhost' identified by '123456'
2、了解库
要使用C语言连接mysql,需要使用mysql官网提供的库,大家可以去官网下载我们使用C接口库来进行连接
要正确使用,我们需要做一些准备工作:
保证mysql服务有效
在官网上下载合适自己平台的mysql connect库,以备后用
方法1:直接下载
下载好后,在linux中是这样的:
解压好后重命名为mysql-connector:进入目录是这样的
这里面最重要的是include头文件、以及库函数,关于头文件、以及动静态库的详细理解,可以看我的这篇博客,有非常详细的对于这些内容的讲述与实验【Linux】文件查找、软硬链接、动静态库_linux 查询 共享库 软连接-CSDN博客
更好的安装办法:
1. 确认是否安装了
libmysqlclient
包步骤 1:检查已安装的包
# 检查是否安装了 MySQL 客户端库的开发包(包含头文件和库) dpkg -l | grep libmysqlclient-dev# 检查是否安装了运行时库(动态库) dpkg -l | grep libmysqlclient
若未安装:
需要手动安装开发包或运行时库。步骤 2:安装
libmysqlclient-dev
sudo apt update sudo apt install libmysqlclient-dev
此包会同时安装运行时库(如
libmysqlclient21
)和开发文件(头文件、静态库)。2. 检查文件路径
安装成功后,库文件应位于以下位置:
(1) 动态库路径
# 动态库文件(.so) ls /usr/lib/x86_64-linux-gnu/libmysqlclient.so*# 示例输出: /usr/lib/x86_64-linux-gnu/libmysqlclient.so # 软链接 /usr/lib/x86_64-linux-gnu/libmysqlclient.so.21 # 实际库文件
(2) 头文件路径
# 头文件(.h) ls /usr/include/mysql/mysql.h
(3) 静态库路径
# 静态库(.a) ls /usr/lib/x86_64-linux-gnu/libmysqlclient.a
引入库:
获得mysql版本信息
程序:
#include<iostream> #include<mysql/mysql.h>int main() {std::cout << "mysql client info: " << mysql_get_client_info() << std::endl;return 0; }
运行结果:显式写出要连接的库-lmysqlclient,如果报错cannot find -lmysqlclient,就使用-L指定库所在的目录。
pupu@VM-8-15-ubuntu:~/test_db$ g++ -o mytest test.cc -lmysql /usr/bin/ld: cannot find -lmysql: No such file or directory collect2: error: ld returned 1 exit status pupu@VM-8-15-ubuntu:~/test_db$ g++ -o mytest test.cc -lmysqlclient pupu@VM-8-15-ubuntu:~/test_db$ ./mytest mysql client info: 8.0.42 pupu@VM-8-15-ubuntu:~/test_db$ g++ -o mytest test.cc -L/lib64/mysql -lmysqlclient pupu@VM-8-15-ubuntu:~/test_db$ ./mytest mysql client info: 8.0.42 pupu@VM-8-15-ubuntu:~/test_db$
如果你的程序报错:ldd mytest,这一行后面可能写的就是not find,这时需要手动将该动态库所对应的路径添加到系统配置文件当中,或者添加到环境变量里(ls /etc/ls.so.conf,添加到这里面),具体操作可以看我的这篇博客
目录-动态库-shared,方法5当中
mysql接口介绍
哪里找需要的接口,先打开mysql官网--->点击导航栏的DOCUMENTATION--->往下看,找到Connetcor & APIs模块---->点击C API---->根据你的mysql版本选择合适的API:
点击对应的版本后进入新的页面,左侧是对应版本的开发引导,介绍:
C API Function Reference,选择后,页面的右侧模块就是对应的方法以及其介绍
C API Basic Interface:C语言基础接口,在用户应用层为使用者创建许多数据结构
mysql常用接口C语言
MySQL提供了完整的C语言API,允许开发者通过C程序与MySQL数据库进行交互。这些API函数封装了连接管理、查询执行、结果处理等核心功能。
连接管理
mysql_init初始化Mysql对象
MYSQL *mysql_init(MYSQL *mysql);
要使用库,必须先进行初始化!!
初始化MYSQL对象
参数:可以是NULL或已有的MYSQL对象指针
返回:初始化后的MYSQL对象指针
见一见mysql库中的mysql结构体对象
mysql_real_connect链接数据库
初始化完毕之后,必须先链接数据库,在进行后续操作。(mysql网络部分是基于TCP/IP的)
MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag );
建立好链接之后,获取英文没有问题,如果获取中文是乱码: //设置链接的默认字符集是utf8,原始默认是latin1
mysql_set_character_set(myfd, "utf8");
建立实际数据库连接
参数依次为:MYSQL对象、主机名、用户名、密码、数据库名、端口号、Unix套接字路径、客户端标志
返回:成功返回MYSQL指针,失败返回NULL
第一个参数 MYSQL是 C api中一个非常重要的变量(mysql_init的返回值),里面内存非常丰富,有port,dbname,charset等连接基本参数。它也包含了一个叫 st_mysql_methods的结构体变量,该变量里面保存着很多函数指针,这些函数指针将会在数据库连接成功以后的各种数据操作中被调用。
mysql_real_connect函数中各参数,基本都是顾名思意。
示例代码:
#include <iostream> #include <mysql/mysql.h> #include <string>const std::string host = "127.0.0.1"; const std::string user = "connector"; const std::string passwd = "123456"; const std::string db = "conn"; const unsigned int port = 3306;int main() {// std::cout << "mysql client info: " << mysql_get_client_info() << std::endl;MYSQL *my = mysql_init(nullptr);if (nullptr == my){std::cerr << "init MySql error" << std::endl;return 1;}if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr){std::cerr << "connect mysql error" << std::endl;return 2;}std::cout << "connect success" << std::endl;mysql_close(my);return 0; }
成功运行:
做实验:当使用指令,systemctl stop mysqld之后,就会失败。
以connector的身份登录mysql,并且使用conn数据库,在conn数据库中创建一个user表:
mysql> desc user; +-----------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+-------------+------+-----+---------+----------------+ | id | bigint | NO | PRI | NULL | auto_increment | | name | varchar(32) | NO | | NULL | | | age | int | NO | | NULL | | | telephone | varchar(32) | YES | UNI | NULL | | +-----------+-------------+------+-----+---------+----------------+ 4 rows in set (0.01 sec)
现在新启一个终端,执行我们刚写的程序:在这里我们可以再直观地看到,我们的程序是连接上数据库了的。
运行结果:
接下来我使用C\C++对这张表进行增删查改操作下sql指令:
查询执行
mysql_query下发mysql命令
int mysql_query(MYSQL *mysql, const char *stmt_str);
执行SQL查询语句
参数:MYSQL对象指针和SQL字符串(要执行的sql语句,如“select * from table”)
返回:0表示成功,非0表示失败
更新程序:
std::cout << "connect success" << std::endl;std::string sql;while (true){std::cout << "Mysql>>> ";if (!std::getline(std::cin, sql) || sql == "quit"){std::cout << "byebye" << std::endl;break;}int n = mysql_query(my, sql.c_str());if (n == 0){std::cout << sql << ", success: " << n << std::endl;}else{std::cerr << "failed: " << n << std::endl;}}
分号可以携带,也可以不携带:
实际情况下,在程序中我们直接下达指令:
//实际情况下我们直接下达指令std::string sql = "update user set name='Jimmy' where id=2";int n = mysql_query(my, sql.c_str());if (n == 0)std::cout << sql << "success" << std::endl;elsestd::cout << sql << "failed" << std::endl;
增删改都可以。那么查呢?
select成功之后,数据显示也要处理;
你们插入文字的时候可能会出现:乱码
显示的使用mysql_set_character_set(my, "utf8");
mysql_store_result获取执行结果
sql执行完以后,如果是查询语句,我们当然还要读取数据,如果update,insert等语句,那么就看下操作成功与否即可。我们来看看如何获取查询结果: 如果mysql_query返回成功,那么我们就通过mysql_store_result这个函数来读取结果。原型如下:
MYSQL_RES *mysql_store_result(MYSQL *mysql);
获取查询结果集
参数:MYSQL对象指针
返回:结果集指针,出错返回NULL
该函数会调用MYSQL变量中的st_mysql_methods中的 read_rows 函数指针来获取查询的结果。同时该函数会返回MYSQL_RES 这样一个变量,该变量主要用于保存查询的结果。同时该函数malloc了一片内存空间来存储查询过来的数据,所以我们一定要记的 free(result),不然是肯定会造成内存泄漏的。 执行完mysql_store_result以后,其实数据都已经在MYSQL_RES 变量中了,下面的api基本就是读取MYSQL_RES 中的数据。
具体存储的结构,与存储的方式:我们可以将这种MYSQL_RES *res 结构看做char**XXX[],->char *XXX[][]。
结果处理
mysql_num_rows获取结果行数
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
从结果集中获取一行数据
参数:结果集指针
返回:行数据数组,无更多行时返回NULL
mysql_num_fields获取结果列数
unsigned int mysql_num_fields(MYSQL_RES *res);
获取结果集中的字段数
参数:结果集指针
返回:字段数量
代码:
MYSQL_RES *res = mysql_store_result(my);if (nullptr == res){std::cerr << "mysql_store_result error" << std::endl;return 4;}my_ulonglong rows = mysql_num_rows(res);my_ulonglong fields = mysql_num_fields(res);std::cout << "行: " << rows << std::endl;std::cout << "列: " << fields << std::endl;
运行结果:
如果执行的语句是,查找某一行:根据我们的要求,会自动取筛选
mysql_fetch_row获取结果内容
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
它会返回一个MYSQL_ROW变量,MYSQL_ROW其实就是char **.就当成一个二维数组来用
示例:
for (int i = 0; i < rows; i++){MYSQL_ROW row = mysql_fetch_row(res);for (int j = 0; j < fields; j++){std::cout << row[j] << "\t";}std::cout << "\n";}
运行结果:
mysql_fetch_fields获取列名
MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res);
示例:
MYSQL_FIELD *fields_array = mysql_fetch_fields(res);for (int i = 0; i < fields; i++){std::cout << fields_array[i].name << "\t";}std::cout << "\n";for (int i = 0; i < rows; i++){MYSQL_ROW row = mysql_fetch_row(res);for (int j = 0; j < fields; j++){std::cout << row[j] << "\t";}std::cout << "\n";}
输出:
mysql_free_result释放掉结果集:
void mysql_free_result(MYSQL_RES *result);
关闭链接
mysql_close 关闭mysql链接
void mysql_close(MYSQL *sock)
错误处理
mysql_error获取最近一次的错误信息
const char *mysql_error(MYSQL *mysql);
获取最近一次操作的错误信息
参数:MYSQL对象指针
返回:错误描述字符串
mysql_errno获得最近一次操作的错误代码
unsigned int mysql_errno(MYSQL *mysql);
获取最近一次操作的错误代码
参数:MYSQL对象指针
返回:错误编号
常用接口完整使用示例
#include <iostream> #include <mysql/mysql.h> #include <string> #include <unistd.h> const std::string host = "127.0.0.1"; const std::string user = "connector"; const std::string passwd = "2738399452Ru@"; const std::string db = "conn"; const unsigned int port = 3306;int main() {// std::cout << "mysql client info: " << mysql_get_client_info() << std::endl;MYSQL *my = mysql_init(nullptr);if (nullptr == my){std::cerr << "init MySql error" << std::endl;return 1;}if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr){std::cerr << "connect mysql error" << std::endl;return 2;}mysql_set_character_set(my, "utf8");std::cout << "connect success" << std::endl;// 实际情况下我们直接下达指令std::string sql = "select * from user";int n = mysql_query(my, sql.c_str());if (n == 0){std::cout << sql << " success" << std::endl;}else{std::cout << sql << "failed" << std::endl;return 3;}MYSQL_RES *res = mysql_store_result(my);if (nullptr == res){std::cerr << "mysql_store_result error" << std::endl;return 4;}int rows = mysql_num_rows(res);int fields = mysql_num_fields(res);std::cout << "行: " << rows << std::endl;std::cout << "列: " << fields << std::endl;MYSQL_FIELD *fields_array = mysql_fetch_fields(res);for (int i = 0; i < fields; i++){std::cout << fields_array[i].name << "\t";}std::cout << "\n";for (int i = 0; i < rows; i++){MYSQL_ROW row = mysql_fetch_row(res);for (int j = 0; j < fields; j++){std::cout << row[j] << "\t";}std::cout << "\n";}// std::string sql;// while (true)// {// std::cout << "Mysql>>> ";// if (!std::getline(std::cin, sql) || sql == "quit")// {// std::cout << "byebye" << std::endl;// break;// }// int n = mysql_query(my, sql.c_str());// if (n == 0)// {// std::cout << sql << ", success: " << n << std::endl;// }// else// {// std::cerr << "failed: " << n << std::endl;// }// }mysql_free_result(res);mysql_close(my);return 0; }
高级功能接口
预处理语句
MYSQL_STMT *mysql_stmt_init(MYSQL *mysql); int mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned long length); int mysql_stmt_execute(MYSQL_STMT *stmt);
预处理语句可以提高性能并防止SQL注入攻击。
事务处理
int mysql_autocommit(MYSQL *mysql, int mode); int mysql_commit(MYSQL *mysql); int mysql_rollback(MYSQL *mysql);
用于控制事务的提交和回滚。
注意事项
使用前确保正确包含MySQL头文件
所有资源使用后必须释放,避免内存泄漏
错误处理不可忽视,应检查每个API调用的返回值
在多线程环境中使用时需注意线程安全问题
Mysql的第3种连接方式图形化界面:
11 款顶级 MySQL 图形化工具汇总,总有一款适合你!(建议收藏)-CSDN博客
Mysql连接池原理与建议网站数据流动是如何进行的图解:
结语:
随着这篇博客接近尾声,我衷心希望我所分享的内容能为你带来一些启发和帮助。学习和理解的过程往往充满挑战,但正是这些挑战让我们不断成长和进步。我在准备这篇文章时,也深刻体会到了学习与分享的乐趣。
在此,我要特别感谢每一位阅读到这里的你。是你的关注和支持,给予了我持续写作和分享的动力。我深知,无论我在某个领域有多少见解,都离不开大家的鼓励与指正。因此,如果你在阅读过程中有任何疑问、建议或是发现了文章中的不足之处,都欢迎你慷慨赐教。
你的每一条反馈都是我前进路上的宝贵财富。同时,我也非常期待能够得到你的点赞、收藏,关注这将是对我莫大的支持和鼓励。当然,我更期待的是能够持续为你带来有价值的内容。