【MySQL】mysql访问

mysql访问

  • 1.引入MySQL 客户端库
  • 2.C/C++ 进行增删改
  • 3.查询的处理细节
  • 4.图形化界面访问数据库
    • 4.1下载MYSQL Workbench
    • 4.2MYSQL Workbench远程连接数据库

在这里插入图片描述

点赞👍👍收藏🌟🌟关注💖💖
你的支持是对我最大的鼓励,我们一起努力吧!😃😃

1.引入MySQL 客户端库

从开始到选择我们用的都是命令行式的mysql访问mysqld,向mysqld下达我们的指令,其实在数据库层面上,连接数据库的客户端除了现在命令行式的客户端,还有图形化界面、网页版的,当然也包括语言级别的库或者包帮我们去访问数据库。

下面我们就用C/C++访问数据库。关于访问数据库我们要做两个准备工作,一是创建一个远端或者本地访问的请求也就是创建一个专门用来进行用C/C++访问客户端的账号。

reate user 'connector'@'localhost' identified by 'xxx';

在这里插入图片描述

然后创建一个数据库,赋予这个账号对数据库中表的所有权限。

在这里插入图片描述

二是安装C/C++要能访问的库,这个库有两种准备,第一种是从官网下载库,

下面这个是用不同语言连接MYSQL,官方提供的库。
在这里插入图片描述
下载推荐的8.0
在这里插入图片描述

我们用的是linux,所以选择linux系统x86 64位

在这里插入图片描述

下载好,上传到linux,然后解压一下,mysql-connector是解压后重命名的

在这里插入图片描述

这是解压后的文件,最重要的就是include 头文件,还有一个lib64 库

在这里插入图片描述

未来头文件给我们提供连接mysql的方法,库 提供连接mysql的库函数

在这里插入图片描述

我们就可以根据头文件,直接调用头文件的的方法,在编译连接的时候把库连入进来。如果忘记怎么引入,在Linux哪里基础IO动静态库就有对应的方法!

但是这种方式不推荐了!之间不是下载mysql,用yum源下载吗。yum源它会给我们找到合适的服务器,客户端,甚至是开发包。所以我们直接在yum哪里去找进行了。

没下载过mysql 可以下一下如果你安装过yum对应msyql源的话,如果不会下请移步于
【MySQL】MySQL在 Linux下环境安装

yum install -y mysql-community-server  

如果你下载过,你就可以看到这里有对应的头文件,未来我们主要用的就是mysql.h

在这里插入图片描述

如果你下载过但是找不到头文件,执行下面的命令,就可以看到了

install -y mysql-devel

mysql库在系统默认安装路径下

在这里插入图片描述

开发环境我们有已经准备好了,接下来我们学习具体的接口。不过我们通过 mysql_get_client_info() 函数,来验证我们的引入是否成功。

#include <iostream>
#include <mysql/mysql.h>

using namespace std;

int main()
{
	//获取当前客户端版本信息
    cout<<"mysql client Version: "<<mysql_get_client_info()<<endl;
    return 0;
}

如果直接编译肯定会报错,说的是未定义的引用,也就是这个mysql_get_client_info()找不到。
在这里插入图片描述

之前基础IO就说过,你要保证这个外来库能被正确连接,gcc/g++默认会选择C和C++的库,虽然你的mysql在系统中,系统也会默认会去/lib64路径下去找,

在这里插入图片描述

但是现在的问题是我怎么知道我需要连接那个库,尽管能找到这个库,但是我怎么知道我们该连那个库呢?所以我们需要需要在编译的时候就指明需要连那个库,

g++ -o mytest test.cc -L/lib64/mysql -lmysqlclient

然后就可以打出来所有mysql客户端的版本,说明这个库就被重新引入了

在这里插入图片描述

以前引入外来库不是还带上面-I选项,今天这里咋没有带。这是因为g++默认会去include里去找。然后拿着代码里的

在这里插入图片描述

去找,所有不会报头文件找不到的问题。如果你非得带-I,就把前面去掉

在这里插入图片描述

g++ -o mytest test.cc -I/usr/include/mysql -L/lib64/mysql -lmysqlclient

接下来我们我们通过这个库它内部给我提供对应的方法来让我们连接mysqld服务端,然后进行访问。

2.C/C++ 进行增删改

接下来我们先认识mysql常用接口。msyql接口介绍

在这里插入图片描述

这里还有mysql库为了方便操作mysql,然后提前在库中给我创建很多的数据结构

在这里插入图片描述

msyql的是一套网络服务,就注定了实际在进行mysql操作之前比如下达sql,一定在之前要连接mysql,而在连接mysql之前,我们还要先来创建一下mysql基础数据结构。要使用库,必须先进行初始化。mysql_init()帮我们创建一个MYSQL对象

MYSQL *mysql_init(MYSQL *mysql);

成功返回MYSQL对象,失败返回nullptr,用的时候必须要调用mysql_close()对应的链接。

在这里插入图片描述

MYSQL是 C api中一个非常重要的变量(mysql_init的返回值),里面内存非常丰富,有port,dbname,charset等连接基本参数。它也包含了一个叫 st_mysql_methods的结构体变量,该变量里面保存着很多函数指针,这些函数指针将会在数据库连接成功以后的各种数据操作中被调用。

MYSQL实际上就是一个结构体里面包含连接mysql相关保存好的一些属性。这相当于FILE*,用来标识mysql客户端一些资源,我们把这些东西可以称之为句柄。

#include <iostream>
#include <mysql/mysql.h>

using namespace std;

int main()
{

    // 1. 初始化mysql,构建mysql对象,得到mysql访问句柄
    MYSQL* my=mysql_init(nullptr);
    if (my == nullptr)
    {
        cerr << "init MySQL error" << endl;
        return 1;
    }


    // 3.用完之后close,释放资源
    mysql_close(my);

    return 0;
}

把数据库对应的MYSQL结构体对象创建初始化好,最终不用它了把它释放。可是要访问mysql之前要先连接数据库,连接数据库的函数。

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 clientflag);

第一个参数就是刚才创建的MYSQL对象。连接成功后把连接成功套接字信息保存到MYSQL对象中。然后要连接的mysql的主机在哪里,用户是谁,密码是多少,连接那个数据库,数据库的端口号是多少,剩下设置为nullptr,0就可以了。

成功时把我们传入的MYSQL给我们返回,失败返回nullptr。

在这里插入图片描述
最开始创建的只允许在本地主机连接数据库的用户就用上了。

#include <iostream>
#include <mysql/mysql.h>
#include <string>

using namespace std;

const string host="localhost"; //host="127.0.0.1" 也是可以的
const string user="connector";
const string passwd="xxx";
const string db="conn";
unsigned int port=xxx; //自己的端口号不要暴露

int main()
{

    // 1. 初始化mysql,构建mysql对象,得到mysql访问句柄
    MYSQL* my=mysql_init(nullptr);
    if (my == nullptr)
    {
        cerr << "init MySQL error" << endl;
        return 1;
    }

    // 2.连接数据库
    if(mysql_real_connect(my,host.c_str(),user.c_str(),passwd.c_str(),db.c_str(),port,nullptr,0) == nullptr)
    {
        cerr << "connect MySQL error" << endl;
        return 2;
    }
	cout<<"connect success"<<endl;

    // 3.用完之后close,释放资源
    mysql_close(my);

    return 0;
}

自此我们完成了连接mysql的第工作

  1. 初始化mysql,构建mysql对象,得到mysql访问句柄
  2. 进行mysql 的connect连接
  3. 用完mysql之后close

然后就可以对mysql下达sql指令了。这个下达sql指令的函数是mysql_query对数据库下达指令。第一个参数就是刚才的MYSQL对象,第二个参数就是下达的sql指令。以前我们在命令行写单sql后面会带;,但是在这里并不需要带;or \g,成功时返回0,失败时返回非0。

在这里插入图片描述

在此之前可以自己先创建一个表

create table user(
     id bigint primary key auto_increment,
     name varchar(32) not null,
     age int not null,
     telphone varchar(32) unique
     );

之前我们学过一个sql指令,查看正在连接数据库的用户

show processlist;

可以看到我们C/C++库确实连接到数据库了

在这里插入图片描述

int main()
{
    // 1. 初始化mysql,构建mysql对象,得到mysql访问句柄
    MYSQL *my = mysql_init(nullptr);
    if (my == nullptr)
    {
        cerr << "init MySQL error" << endl;
        return 1;
    }

    // 2.连接数据库
    if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr << "connect MySQL error" << endl;
        return 2;
    }
    // cout<<"connect success"<<endl;

    string sql;
    while (true)
    {
        cout << " mysql> ";
        if (!getline(cin, sql) || sql == "quit")
        {
            cout << "Bye" << endl;
            break;
        }

        int n = mysql_query(my, sql.c_str());
        if (n == 0)
        {
            cout << sql << " success" << endl;
        }
        else
        {
            cerr << sql << " error" << endl;
            return 3;
        }
    }

    // 3.用完之后close,释放资源
    mysql_close(my);

    return 0;
}

这里名字我们先输入英文,具体原因等会说。下达的这个sql执行可带;或者不带;。然后看到我们确实把信息插入到数据库了。我们其实也可以自己搞一个mysql的客户端。但是实际上我们也不会这样做,别人自己有客户端。我们直接向数据库下达sql指令就行了。

在这里插入图片描述

更新

int main()
{
    // 1. 初始化mysql,构建mysql对象,得到mysql访问句柄
    MYSQL *my = mysql_init(nullptr);
    if (my == nullptr)
    {
        cerr << "init MySQL error" << endl;
        return 1;
    }

    // 2.连接数据库
    if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr << "connect MySQL error" << endl;
        return 2;
    }
    
    string sql="update user set name='jim' where id=2";
    int n=mysql_query(my,sql.c_str());
    if(n == 0) cout<<sql<<" success"<<endl;
    else cout<<sql<<" error"<<endl;

    // 3.用完之后close,释放资源
    mysql_close(my);

    return 0;
}

执行一下,看到id=2的名字确实更新为jim了。

在这里插入图片描述

所以未来我们所写的任何的关于数据库方面的程序,你想使用数据库,你可以提前建好数据库账号然后赋权,并且建表。然后编写对应C/C++代码。然后就可以为你的上层进行数据层面上的支撑了。

插入

int main()
{
    // 1. 初始化mysql,构建mysql对象,得到mysql访问句柄
    MYSQL *my = mysql_init(nullptr);
    if (my == nullptr)
    {
        cerr << "init MySQL error" << endl;
        return 1;
    }

    // 2.连接数据库
    if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr << "connect MySQL error" << endl;
        return 2;
    }
    
    //string sql="update user set name='jim' where id=2";
    string sql="insert into user (name,age,telphone) values ('peter',19,19187654321)";
    int n=mysql_query(my,sql.c_str());
    if(n == 0) cout<<sql<<" success"<<endl;
    else cout<<sql<<" error"<<endl;

    // 3.用完之后close,释放资源
    mysql_close(my);

    return 0;
}

在这里插入图片描述

删除

int main()
{
    // 1. 初始化mysql,构建mysql对象,得到mysql访问句柄
    MYSQL *my = mysql_init(nullptr);
    if (my == nullptr)
    {
        cerr << "init MySQL error" << endl;
        return 1;
    }

    // 2.连接数据库
    if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr << "connect MySQL error" << endl;
        return 2;
    }
    
    //string sql="update user set name='jim' where id=2";
    //string sql="insert into user (name,age,telphone) values ('peter',19,19187654321)";
    string sql="delete from user where id=1";
    int n=mysql_query(my,sql.c_str());
    if(n == 0) cout<<sql<<" success"<<endl;
    else cout<<sql<<" error"<<endl;

    // 3.用完之后close,释放资源
    mysql_close(my);

    return 0;
}

在这里插入图片描述

单sql本身就是事务,mysql默认事务提交是自动的,所以今天你可以用一个连接访问数据库,也可以创建十个连接访问数据库,你可以用命令行方式访问数据库,也可以用C/C++访问数据库。所以数据库可以存在多个访问,因为有事务,事务有ACID能保证原子性等等。所以我们在应用层就不用担心业务代码执行时出现问题。

mysql_query这个函数现在可以增删改,那查行不行呢?

int main()
{
    // 1. 初始化mysql,构建mysql对象,得到mysql访问句柄
    MYSQL *my = mysql_init(nullptr);
    if (my == nullptr)
    {
        cerr << "init MySQL error" << endl;
        return 1;
    }

    // 2.连接数据库
    if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr << "connect MySQL error" << endl;
        return 2;
    }
    
    //string sql="update user set name='jim' where id=2";
    //string sql="insert into user (name,age,telphone) values ('peter',19,19187654321)";
    //string sql="delete from user where id=1";
    string sql="select * from user";
    int n=mysql_query(my,sql.c_str());
    if(n == 0) cout<<sql<<" success"<<endl;
    else cout<<sql<<" error"<<endl;

    // 3.用完之后close,释放资源
    mysql_close(my);

    return 0;
}

别人告诉我成功了啊,然后呢?

在这里插入图片描述

在我们数据库语句中,增删改是最简单的,因为增删改只需要保证成功即可,那么增删改操作一定能完成。而select是最不好处理的,因为当成功执行select语句,只是执行完sql第一步,那select后的数据在那呢?你是不是要把数据给显示处理或者说让用户获取到,所以还需要在做后面的工作。所以select还有后序获取数据包括把数据在交给它的调用层。而不像增删改执行完就完了。

还有一个问题,刚刚在插入的时候,name插入都是英文,那我们插入中文会怎么样呢?

int main()
{
    // 1. 初始化mysql,构建mysql对象,得到mysql访问句柄
    MYSQL *my = mysql_init(nullptr);
    if (my == nullptr)
    {
        cerr << "init MySQL error" << endl;
        return 1;
    }

    // 2.连接数据库
    if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr << "connect MySQL error" << endl;
        return 2;
    }
    
    //string sql="update user set name='jim' where id=2";
    //string sql="insert into user (name,age,telphone) values ('peter',19,19187654321)";
    string sql="insert into user (name,age,telphone) values ('张三',18,11187654321)";
    //string sql="delete from user where id=1";
    //string sql="select * from user";
    int n=mysql_query(my,sql.c_str());
    if(n == 0) cout<<sql<<" success"<<endl;
    else cout<<sql<<" error"<<endl;

    // 3.用完之后close,释放资源
    mysql_close(my);

    return 0;
}

我们插入中文时乱码了

在这里插入图片描述

乱码问题怎么解决?我们的数据库编码格式都配过是utf8的。出现乱码问题,一定是因为客户端和服务端对编码问题没有形成一致。比如说服务端用的是utf8,客户端用的是latin1。因为我们数据库编码都是utf8的,所以一定是客户端出现了问题。

建立好链接之后,获取英文没有问题,如果获取中文是乱码:设置链接的默认字符集是utf8,原始默认是latin1

int main()
{
    // 1. 初始化mysql,构建mysql对象,得到mysql访问句柄
    MYSQL *my = mysql_init(nullptr);
    if (my == nullptr)
    {
        cerr << "init MySQL error" << endl;
        return 1;
    }

    // 2.连接数据库
    if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr << "connect MySQL error" << endl;
        return 2;
    }
    
    // 设置编码格式
    mysql_set_character_set(my, "utf8");
    
    //string sql="update user set name='jim' where id=2";
    //string sql="insert into user (name,age,telphone) values ('peter',19,19187654321)";
    string sql="insert into user (name,age,telphone) values ('李四',18,12187654321)";
    //string sql="delete from user where id=1";
    //string sql="select * from user";
    int n=mysql_query(my,sql.c_str());
    if(n == 0) cout<<sql<<" success"<<endl;
    else cout<<sql<<" error"<<endl;

    // 3.用完之后close,释放资源
    mysql_close(my);

    return 0;
}

设置好编码,在插入中文就没问题了。

在这里插入图片描述

自此我们就已经能够进行mysql对象初始化,mysql的连接,mysql的关闭,以及通过mysql_query向数据库下达对应的指令了。下面我们就解决拿到select的数据问题。

3.查询的处理细节

查sql本身能够被正确执行,但是执行之后怎么把查的数据交给上层返回给客户或者把它的数据显示处理呢?那在执行select的时候要把select的结果通过mysql_query查完之后把结果应该让我们怎么获取到呢?实际上mysql_query在执行select的时候会把结果保存到MYSQL这个句柄中。这个句柄是一个结构体它本身里面会包含对应的保存数据的缓存区区域。但是这部分数据依旧要被我们提取出来的。我们通过mysql_store_result这个函数来将结果进行转储。这个函数提取并且转储到结果集中。会把结果按照条目放置好。

在这里插入图片描述

是从MYSQL这个句柄中把结果转储到MYSQL_RES这个结构中。

在这里插入图片描述

把查询结果按照行为单位,全部都放进结果集中。

在这里插入图片描述

成功返回MYSQL_RES对象,失败返回nullptr。也可以采用mysql_errno和mysql_error来进行判断出错原因。

在这里插入图片描述

下面我们看看怎么用这个函数

首先先将结果转储到MYSQL_RES结构体中。

int main()
{
    // 1. 初始化mysql,构建mysql对象,得到mysql访问句柄
    MYSQL *my = mysql_init(nullptr);
    if (my == nullptr)
    {
        cerr << "init MySQL error" << endl;
        return 1;
    }

    // 2.连接数据库
    if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr << "connect MySQL error" << endl;
        return 2;
    }
    // cout<<"connect success"<<endl;

    // 设置编码格式
    mysql_set_character_set(my, "utf8");

    string sql="select * from user";
    int n=mysql_query(my,sql.c_str());
    if(n == 0) 
    {
        cout<<sql<<" success"<<endl;
    }
    else
    {
        cout<<sql<<" error"<<endl;
        return 3;
    } 

	//转储
    MYSQL_RES* res=mysql_store_result(my);
    if(res == nullptr)
    {
        cerr<<"mysql_store_result error"<<endl;
        return 4;
    }


    // 3.用完之后close,释放资源
    mysql_close(my);

    return 0;
}

那MYSQL_RES这个结构体应该如何理解呢?

首先我们要知道我们查出来的是一种表结构,表结构中行列关系是我们打印出来的,尤其是这些分割符,这些东西我们自己打印出来的,并不是在mysql在表中真实存在的。
在这里插入图片描述

在mysql表中其实存在两类信息,一类是存储表结构中的列属性或者列名称,还有一类是存储表中的内容。

在这里插入图片描述
我们先看内容,这些内容以一定格式先放到MYSQL结构体对象内部,然后在转储到MYSQL_RES结构中。转储是为了更好的便于做二次处理。

在表中查出来的数据,就一定是在MYSQL内部在内存中保存这部分内容的。mysql将所有数据,读取出来的时候,全部都当作字符串。 虽然以前它们什么int,char等,但是一旦把数据读到自定义缓存区中的时候,那么它一定是把所有数据都当作字符串来看待。以前约束类型只是在插入的时候要处理,读取出来当当作字符串处理。

然后MYSQL_RES要把结果归置一下,我可以把MYSQL_RES想象成一个存着char**的指针数组。数组大小代表筛选出来的数据记录有多少行。一条记录里面有多列,每一列都是字符串。

在这里插入图片描述

然后这个数组中每一个char** 指针都指向一个存访char类型的指针数组,指向的是这个数组中首个元素的地址。char** 的指针数组大小代表的是数据记录有多少行,而每一行char 的指针数组里的char* 依次指向一条记录的每一列。

在这里插入图片描述

所以未来想提取一整行,想提取一整行中的列,我可以按照行列去提取!

我们可以把MYSQL_RES当作一个char**xx[]数组去理解,或者当作一个char*[][]数组去理解都可以,怎么方便怎么来。纵向去遍历每一行,横向去遍历一行中每一列。就可以找所有查询结果都找到。

在这里插入图片描述

未来MYSQL_RES就以这样的方式把查询的结果保存起来。

那结果最终怎么遍历呢?首先我们要知道这个转储的结果有多少行,有多少列!然后按照行列去遍历。

获取结果行数mysql_num_rows
参数是MYSQL_RES,从MYSQL_RES结果集中拿结果有多少行。

my_ulonglong mysql_num_rows(MYSQL_RES *res);

获取结果列数mysql_num_fields

unsigned int mysql_num_fields(MYSQL_RES *res);
int main()
{
    // 1. 初始化mysql,构建mysql对象,得到mysql访问句柄
    MYSQL *my = mysql_init(nullptr);
    if (my == nullptr)
    {
        cerr << "init MySQL error" << endl;
        return 1;
    }

    // 2.连接数据库
    if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr << "connect MySQL error" << endl;
        return 2;
    }
    // cout<<"connect success"<<endl;

    // 设置编码格式
    mysql_set_character_set(my, "utf8");

    string sql="select * from user";
    int n=mysql_query(my,sql.c_str());
    if(n == 0) 
    {
        cout<<sql<<" success"<<endl;
    }
    else
    {
        cout<<sql<<" error"<<endl;
        return 3;
    } 

    MYSQL_RES* res=mysql_store_result(my);
    if(res == nullptr)
    {
        cerr<<"mysql_store_result error"<<endl;
        return 4;
    }

    my_ulonglong row=mysql_num_rows(res);
    my_ulonglong col=mysql_num_fields(res);
    
    cout << "行: " << rows << endl;
    cout << "列: " << cols << endl;

    // 3.用完之后close,释放资源
    mysql_close(my);

    return 0;
}

目前这个表不就是3行4列吗

在这里插入图片描述

那结果怎么拿?遍历每一行每一列。一行一列的把结果都拿到。
mysql为了很好的支持遍历,它内部还提供一种数据结构叫做MYSQL_ROW,每次拿到一行。

获取结果内容mysql_fetch_row

MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);

这个函数就向以前学过的迭代器,当我们第一次调用mysql_fetch_row它内部会为我们维护当前遍历的第一行,把第一行的结果集以MYSQL_ROW形式返回。当遍历第二行的时候,只需要在调用一次mysql_fetch_row,不用自己维护行下标,它会自动指向下一行。就如迭代器一样,只需要按照特定的次数进行遍历调用就会依次把元素遍历一遍,特别像迭代器。

可以看到MYSQL_ROW其实就是一个char指针,因为只有char才能指向第一行第二行等等。
在这里插入图片描述

int main()
{
    // 1. 初始化mysql,构建mysql对象,得到mysql访问句柄
    MYSQL *my = mysql_init(nullptr);
    if (my == nullptr)
    {
        cerr << "init MySQL error" << endl;
        return 1;
    }

    // 2.连接数据库
    if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr << "connect MySQL error" << endl;
        return 2;
    }
    // cout<<"connect success"<<endl;

    // 设置编码格式
    mysql_set_character_set(my, "utf8");

    string sql = "select * from user";
    int n = mysql_query(my, sql.c_str());
    if (n == 0)
    {
        cout << sql << " success" << endl;
    }
    else
    {
        cout << sql << " error" << endl;
        return 3;
    }

    MYSQL_RES *res = mysql_store_result(my);
    if (res == nullptr)
    {
        cerr << "mysql_store_result error" << endl;
        return 4;
    }

    //下面都是和结果集有关的, MYSQL_RES
    my_ulonglong rows = mysql_num_rows(res);
    my_ulonglong cols = mysql_num_fields(res);

    cout << "行: " << rows << endl;
    cout << "列: " << cols << endl;

	//拿结果  
    for(int i=0;i<rows;++i)
    {
        MYSQL_ROW line=mysql_fetch_row(res);
        for(int j=0;j<cols;++j)
        {
            cout<<line[j]<<"\t"; 
        }
        cout<<endl;

    }

        // 3.用完之后close,释放资源
        mysql_close(my);

    return 0;
}

现在我们就可以把select的结果都拿到了!

在这里插入图片描述

刚才说了在获取msyql表内容的时候,我们除了获取表格中内容,它的列属性我们也想获取。想知道它是那一列的,或者想知道当前查的是那张表,那个数据库。怎么办呢?我们有另一个接口。

获取列名mysql_fetch_fields

MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res);

与mysql_fetch_fields相对的还有一个mysql_fetch_field接口,mysql_fetch_fields以数组形式返回的是所有的列属性对应的结构体。每一列属性都是一个结构体。
mysql_fetch_field可以让你依次遍历所有列,以列为单位,第一次是第一列,第二次是第二列,也就像迭代器。

在这里插入图片描述

这里我们就不麻烦了,直接一次获得所有列属性。然后可以遍历所有列把列名称打印出来。

int main()
{
    // 1. 初始化mysql,构建mysql对象,得到mysql访问句柄
    MYSQL *my = mysql_init(nullptr);
    if (my == nullptr)
    {
        cerr << "init MySQL error" << endl;
        return 1;
    }

    // 2.连接数据库
    if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr << "connect MySQL error" << endl;
        return 2;
    }
    // cout<<"connect success"<<endl;

    // 设置编码格式
    mysql_set_character_set(my, "utf8");

    string sql = "select * from user";
    int n = mysql_query(my, sql.c_str());
    if (n == 0)
    {
        cout << sql << " success" << endl;
    }
    else
    {
        cout << sql << " error" << endl;
        return 3;
    }

    MYSQL_RES *res = mysql_store_result(my);
    if (res == nullptr)
    {
        cerr << "mysql_store_result error" << endl;
        return 4;
    }

    //下面都是和结果集有关的, MYSQL_RES
    my_ulonglong rows = mysql_num_rows(res);
    my_ulonglong cols = mysql_num_fields(res);

    cout << "行: " << rows << endl;
    cout << "列: " << cols << endl;

    //属性
    MYSQL_FIELD* fields=mysql_fetch_fields(res);

    for(int i=0;i<cols;++i)
    {
        cout<<fields[i].name<<"\t";
    }
    cout<<endl;


    //内容
    for(int i=0;i<rows;++i)
    {
        MYSQL_ROW line=mysql_fetch_row(res);
        for(int j=0;j<cols;++j)
        {
            cout<<line[j]<<"\t"; 
        }
        cout<<endl;

    }
    
        // 3.用完之后close,释放资源
        mysql_close(my);

    return 0;
}

自此列名称我们就拿到了。

在这里插入图片描述
如果你将来想获取什么属性就直接去获取。

int main()
{
    // 1. 初始化mysql,构建mysql对象,得到mysql访问句柄
    MYSQL *my = mysql_init(nullptr);
    if (my == nullptr)
    {
        cerr << "init MySQL error" << endl;
        return 1;
    }

    // 2.连接数据库
    if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr << "connect MySQL error" << endl;
        return 2;
    }
    // cout<<"connect success"<<endl;

    // 设置编码格式
    mysql_set_character_set(my, "utf8");

    string sql = "select * from user";
    int n = mysql_query(my, sql.c_str());
    if (n == 0)
    {
        cout << sql << " success" << endl;
    }
    else
    {
        cout << sql << " error" << endl;
        return 3;
    }

    MYSQL_RES *res = mysql_store_result(my);
    if (res == nullptr)
    {
        cerr << "mysql_store_result error" << endl;
        return 4;
    }

    //下面都是和结果集有关的, MYSQL_RES
    my_ulonglong rows = mysql_num_rows(res);
    my_ulonglong cols = mysql_num_fields(res);

    cout << "行: " << rows << endl;
    cout << "列: " << cols << endl;

    //属性
    MYSQL_FIELD* fields=mysql_fetch_fields(res);

    for(int i=0;i<cols;++i)
    {
        cout<<fields[i].name<<"\t";
    }
    cout<<endl;


    //内容
    for(int i=0;i<rows;++i)
    {
        MYSQL_ROW line=mysql_fetch_row(res);
        for(int j=0;j<cols;++j)
        {
            cout<<line[j]<<"\t"; 
        }
        cout<<endl;
    }
    
    cout<<fields[0].db<<" "<<fields[0].table<<endl;

    
     // 3.用完之后close,释放资源
      mysql_close(my);

    return 0;
}

在这里插入图片描述

最终我们就把mysql的查询结果获取到,然后转储到结果集,然后从结果集中提取行列,还有其他属性和内容。现在我们对增删查改就有一个完整的认识了。

但是还有一个细节mysql_store_result会把查询结果由MYSQL转储到MYSQL_RES里,MYSQL_RES一定要为我们malloc一大堆空间,所以我们一定要记的 free(result),不然是肯定会造成内存泄漏的。我们不能直接用C的free或者C++的delete,而用的是mysql库提供的这个函数,把结果集中空间释放掉。

在这里插入图片描述
在这里插入图片描述

int main()
{
    // 1. 初始化mysql,构建mysql对象,得到mysql访问句柄
    MYSQL *my = mysql_init(nullptr);
    if (my == nullptr)
    {
        cerr << "init MySQL error" << endl;
        return 1;
    }

    // 2.连接数据库
    if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr << "connect MySQL error" << endl;
        return 2;
    }
    // cout<<"connect success"<<endl;

    // 设置编码格式
    mysql_set_character_set(my, "utf8");

    string sql = "select * from user";
    int n = mysql_query(my, sql.c_str());
    if (n == 0)
    {
        cout << sql << " success" << endl;
    }
    else
    {
        cout << sql << " error" << endl;
        return 3;
    }

    MYSQL_RES *res = mysql_store_result(my);
    if (res == nullptr)
    {
        cerr << "mysql_store_result error" << endl;
        return 4;
    }

    //下面都是和结果集有关的, MYSQL_RES
    my_ulonglong rows = mysql_num_rows(res);
    my_ulonglong cols = mysql_num_fields(res);

    cout << "行: " << rows << endl;
    cout << "列: " << cols << endl;

    //属性
    MYSQL_FIELD* fields=mysql_fetch_fields(res);

    for(int i=0;i<cols;++i)
    {
        cout<<fields[i].name<<"\t";
    }
    cout<<endl;


    //内容
    for(int i=0;i<rows;++i)
    {
        MYSQL_ROW line=mysql_fetch_row(res);
        for(int j=0;j<cols;++j)
        {
            cout<<line[j]<<"\t"; 
        }
        cout<<endl;
    }
    
    cout<<fields[0].db<<" "<<fields[0].table<<endl;

     //释放结果集
     mysql_free_result(res);

     // 3.用完之后close,释放资源
      mysql_close(my);

    return 0;
}

可以看到对于读取的处理其实是挺麻烦的。

我们常用的接口就这些,对于一般数据库读取没有任何问题。

最后,mysql C api还支持事务等常用操作,大家下来自行了解:

my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode);
my_bool STDCALL mysql_commit(MYSQL * mysql);
my_bool STDCALL mysql_rollback(MYSQL * mysql)

目前为止所有连接数据库的操作,我们已经有第二种方案。以前就是mysql命令行式的、刚刚就是mysql的C/C++的连接方案,我们还可以通过图形化界面连接数据库。

4.图形化界面访问数据库

这里推荐几个好用的图形化界面。

Nacicat是一个桌面版的mysql数据库管理和开发工具,以图形化界面显示数据库的操作。虽然这个工具非常好用,但遗憾的是,这个软件是收费的。可以自己在网上找找它的破解版。

在这里插入图片描述
SQLyog 也是一个易于使用的、快速而简洁的图形化管理MYSQL数据库的工具,它能够在任何地点有效地管理你的数据库。但同样的,虽然它用起来很舒服,但它也是收费的
在这里插入图片描述
MYSQL Workbench是mysql官方提供的数据库管理和开发工具,支持图形化界面。虽然它在使用上并没有上面的Navicat和SQLyog好用,但优点就是它是免费的。这里我们重点就用它。

4.1下载MYSQL Workbench

我们可以直接去mysql官网上去找到它,然后下载。

在这里插入图片描述

往下翻找到这个然后进去

在这里插入图片描述

找到MySQL Workbench然后进去

在这里插入图片描述

选择对应的操作系统,直接下载就行了

在这里插入图片描述

下好之后运行就是这个样子

在这里插入图片描述

4.2MYSQL Workbench远程连接数据库

MYSQL Workbench也是一个客户端,说白了它和我们自己写的C/C++客户端和曾经mysql对应的命令行客户端是没有任何差别的,它也要进行网络请求,也要进行登录。所以mysql一定要允许这个用户进行远程登录。

因此我们在创建一个允许远程登录的账号。
创建一个允许用户从任意地点登录。这个任意登录这件事情,虽然我们这样写了,一般在公司内允许那一台机器访问数据库可以把这个IP地址确定下来不用填%,今天我们用的云服务器,我们内网经过NAT路由器转发IP地址会发生改变。本地IP配上去没有任何意义,所以这里只能用%。

create user 'workbench'@'%' identified by 'xxx';

然后在给新用户赋权。把conn数据库所有表的权限都给这个用户。

grant all on conn.* to 'workbench'@'%';

然后才能远程连接,点击这里+,配置一下相关信息

在这里插入图片描述

我们主要填的就是IP地址,端口号,和用户。还可以给这个连接起个名字。

在这里插入图片描述

配置好,然后点击下面的,代表测试一下连接,它会要求输入对应的密码,直接把这个用户的密码输入就行了。

在这里插入图片描述

如果成功连接在点击ok就是下面这样,如果连接不上可能是你端口号没有放出来。自己放一下。如果想登录的话,点击一下这个出来的东西,然后就登录进去了。

在这里插入图片描述

进去之后我们可以看到对应表结构、视图,存储过程和函数这些。我们现在只用关系表结构就可以了。表结构里面对应的列、索引、外键、触发器这些。

在这里插入图片描述

列里面可以看到对应列的属性,如id列的主机和自增长

在这里插入图片描述

下面我们可以在框里写一些sql指令了。写完之后选中或者光标放在你写的sql这里然后点击这个闪电执行它。然后下面就可以看到对应的信息。

在这里插入图片描述

虽然光标放在后面点击闪电也可以执行,但是它是从上到下开始执行的,如果只需要执行某一个sql指令,还是要选择它然后在去执行。

在这里插入图片描述

接下来我们可以一下这个表,可以看到这里担心数据太多,默认只把0-1000行筛选出来。

在这里插入图片描述

然后可以直接在这里对数据进行插入,然后再点击Apply执行一下

在这里插入图片描述

Apply会把刚刚在图形化界面这里做的动作变成sql的语句,然后在点Apply执行。

在这里插入图片描述

然后在点Finsh,这个插入就算真正执行完成了

在这里插入图片描述

然后我们查一下,确实看到是插入了

在这里插入图片描述

接下里我们想把张三这条记录删除一下,可以直接在图形化界面删除,然后还是和上面一样的流程Apply。

在这里插入图片描述

然后这看到确实可以删除。

在这里插入图片描述

更新也是一样在图形化界面改,然后Apply执行一下。我们把李四年龄改成90岁。

在这里插入图片描述

看到确实也是改了

在这里插入图片描述

换言之,我们就不用自己写sql了,拿到表结构对它进行增删查改,直接在里面手改就行了。这就是图形化界面的好处。

如果想把自己写的一大堆sql指令保存一下,可以ctrl+s保存。形成一个.sql文件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/774878.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据特征采样在 MySQL 同步一致性校验中的实践

作者&#xff1a;vivo 互联网存储研发团队 - Shang Yongxing 本文介绍了当前DTS应用中&#xff0c;MySQL数据同步使用到的数据一致性校验工具&#xff0c;并对它的实现思路进行分享。 一、背景 在 MySQL 的使用过程中&#xff0c;经常会因为如集群拆分、数据传输、数据聚合等…

C++ 仿QT信号槽二

// 实现原理 // 每个signal映射到bitset位&#xff0c;全集 // 每个slot做为signal的bitset子集 // signal全集触发&#xff0c;标志位有效 // flip将触发事件队列前置 // slot检测智能指针全集触发的标志位&#xff0c;主动运行子集绑定的函数 // 下一帧对bitset全集进行触发清…

CUDA编程基础

文章目录 1、GPU介绍2、CUDA程序进行编译3、CUDA线程模型3.1、一维网格一维线程块3.2、二维网格二维线程块3.3、三维网格三维线程块3.3、不同组合形式 4、nvcc编译流程5、CUDA程序基本架构6、错误检测函数6.1、运行时API错误代码6.2、检查核函数 7、CUDA记时7.1、记时代码7.2、…

基于Python爬虫的城市二手房数据分析可视化

基于Python爬虫的城市二手房数据分析可视化 一、前言二、数据采集(爬虫,附完整代码)三、数据可视化(附完整代码)3.1 房源面积-总价散点图3.2 各行政区均价3.3 均价最高的10个小区3.4 均价最高的10个地段3.5 户型分布3.6 词云图四、如何更换城市一、前言 二手房具有价格普…

博途通讯笔记1:1200与1200之间S7通讯

目录 一、添加子网连接二、创建PUT GET三、各个参数的意义 一、添加子网连接 二、创建PUT GET 三、各个参数的意义

换根dp,CF 633F - The Chocolate Spree

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 633F - The Chocolate Spree 二、解题报告 1、思路分析 2600的题&#xff0c;但是不算很困难。 先考虑暴力做法&#xff0c;如何得到两条不相交的路径&#xff1f; 枚举删除的边&#xff0c;得到两棵子树…

鼠标自动点击器怎么用?鼠标连点器入门教程!

鼠标自动点击器是适用于Windows电脑的自动执行鼠标点击操作的工具&#xff0c;主要用于模拟鼠标点击操作&#xff0c;实现鼠标高速点击的操作。通过模拟鼠标点击&#xff0c;可以在用户设定的位置、频率和次数下自动执行点击动作。 鼠标自动点击器主要的应用场景&#xff1a; …

数据操作10-15题(30 天 Pandas 挑战)

数据操作 1. 相关知识点1.12 分组与连表1.13 排名 2. 题目2.10 第N高的薪水2.11 第二高的薪水2.12 部门工资最高的员工2.13 分数排名2.14 删除重复的电子邮箱2.15 每个产品在不同商店的价格 1. 相关知识点 1.12 分组与连表 分组max_salaryemployee.groupby(departmentId)[sal…

超简易SpringBoot工程构建与部署 ( 图解 - 零基础专属 )

目录 简单了解MVC架构 模型&#xff08;Model&#xff09; 视图&#xff08;View&#xff09; 控制器&#xff08;Controller&#xff09; 基本环境准备 MYSQL建库建表 创库创表 智能生成数据 创建SpringBoot项目 配置pox.xml 代码提供 补充(IDEA的Maven要配置正确…

用kimi和claude自动生成时间轴图表

做时间轴图表并不难&#xff0c;但是很麻烦&#xff0c;先要大量收集相关事件&#xff0c;然后在一些图表软件中反复调整操作。现在借助AI工具&#xff0c;可以自动生成了。 首先&#xff0c;在kimi中输入提示词来获取某个企业的大事记&#xff1a; 联网检索&#xff0c;元语…

前后端数据交互流程

一、前言 用户在浏览器访问一个网站时&#xff0c;会有前后端数据交互的过程&#xff0c;前后端数据交互也有几种的情况&#xff0c;一下就简单的来说明一下 二、原理 介绍前后端交互前先来了解一下浏览器的功能&#xff0c;浏览器通过渲染引擎和 JavaScript 引擎协同工作&am…

uboot ethernet初始化

在Board_r.c 使用initr_net,先初始化phy,然后初始化gmac,driver/net/gmacv300/gmac.c实现管脚复用和gmac设备注册 Board_r.c #ifdef CONFIG_CMD_NETstatic int initr_net(void){puts("Net: ");eth_initialize();#if defined(CONFIG_RESET_PHY_R)debug("Reset…

计算机视觉 图像融合技术概览

在许多计算机视觉应用中(例如机器人运动和医学成像),需要将来自多幅图像的相关信息集成到一幅图像中。这种图像融合将提供更高的可靠性、准确性和数据质量。 多视图融合可以提高图像的分辨率,同时恢复场景的 3D 表示。多模态融合结合了来自不同传感器的图像,称为多传感器融…

短视频文案提取神器怎么提取抖音视频文案!

很多编导以及视频内容创作者为了提高自己的工作效率还会使用视频转文字提取神器&#xff0c;我们都清楚短视频领域每个平台人群熟悉都有所不同&#xff0c;在分发内容的时候也会调整内容已符合平台属性。 短视频文案提取神器怎么提取抖音视频文案 短视频常见的平台有抖音、西瓜…

SpringBoot实战:轻松实现XSS攻击防御(注解和过滤器)

文章目录 引言一、XSS攻击概述1.1 XSS攻击的定义1.2 XSS攻击的类型1.3 XSS攻击的攻击原理及示例 二、Spring Boot中的XSS防御手段2.1 使用注解进行XSS防御2.1.1 引入相关依赖2.1.2 使用XSS注解进行参数校验2.1.3 实现自定义注解处理器2.1.4 使用注解 2.2 使用过滤器进行XSS防御…

现在这个行情怎么理解股票期权?一个守住底线的工具!

今天带你了解现在这个行情怎么理解股票期权&#xff1f;一个守住底线的工具&#xff01;股票期权是一种金融衍生品&#xff0c;给予持有者在未来特定时间以特定价格购买或出售股票的权利。 行情看down可以买入看跌期权&#xff0c;看跌期权的买方是因为预计行情的价格会在近期…

imx6ull/linux应用编程学习(11)CAN应用编程基础

关于裸机的can通信&#xff0c;会在其他文章发&#xff0c;这里主要讲讲linux上的can通信。 与I2C,SPI等同步通讯方式不同&#xff0c;CAN通讯是异步通讯&#xff0c;也就是没有时钟信号线来保持信号接收同步&#xff0c;也就是所说的半双工&#xff0c;无法同时发送与接收&…

【python】PyQt5控件尺寸大小位置,内容边距等API调用方法实战解析

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

小(微)间距P1.538COB渠道现货销售将加速全面升级替换SMD产品。

COB&#xff08;Chip on Board&#xff09;技术&#xff0c;如一颗璀璨的星辰&#xff0c;在上世纪60年代的科技夜空中悄然升起。它巧妙地将LED芯片镶嵌在PCB电路板的怀抱中&#xff0c;再用特种树脂为其披上一层坚韧的外衣&#xff0c;宛如一位精心雕琢的艺术家在创作一幅完美…