【MySQL】视图、用户管理、MySQL使用C\C++连接

发布于:2025-06-08 ⋅ 阅读:(14) ⋅ 点赞:(0)

 📚 博主的专栏

🐧 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';

关键注意事项

  1. 最小权限原则
    避免使用ALL PRIVILEGES%主机,按需分配权限以降低安全风险。

  2. 认证插件兼容性
    若客户端不支持caching_sha2_password,需显式指定mysql_native_password

  3. 权限生效机制

    • GRANT/REVOKE命令自动生效。

    • 手动修改权限表后需执行FLUSH PRIVILEGES;

  4. 登录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;
    else
        std::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);

用于控制事务的提交和回滚。

注意事项

  1. 使用前确保正确包含MySQL头文件

  2. 所有资源使用后必须释放,避免内存泄漏

  3. 错误处理不可忽视,应检查每个API调用的返回值

  4. 在多线程环境中使用时需注意线程安全问题

Mysql的第3种连接方式图形化界面:

11 款顶级 MySQL 图形化工具汇总,总有一款适合你!(建议收藏)-CSDN博客

Mysql连接池原理与建议网站数据流动是如何进行的图解:

结语:

       随着这篇博客接近尾声,我衷心希望我所分享的内容能为你带来一些启发和帮助。学习和理解的过程往往充满挑战,但正是这些挑战让我们不断成长和进步。我在准备这篇文章时,也深刻体会到了学习与分享的乐趣。    

         在此,我要特别感谢每一位阅读到这里的你。是你的关注和支持,给予了我持续写作和分享的动力。我深知,无论我在某个领域有多少见解,都离不开大家的鼓励与指正。因此,如果你在阅读过程中有任何疑问、建议或是发现了文章中的不足之处,都欢迎你慷慨赐教。

        你的每一条反馈都是我前进路上的宝贵财富。同时,我也非常期待能够得到你的点赞、收藏,关注这将是对我莫大的支持和鼓励。当然,我更期待的是能够持续为你带来有价值的内容。


网站公告

今日签到

点亮在社区的每一天
去签到