0


【MySQL】C/C++代码操作数据库

简单尝试使用c语言的库对mysql的数据进行增删改查

1.新增数据库和表

刚开始数据库没有设定密码和用户,直接用root用户登录

mysql -uroot;

创建一个

hello

数据库,并进入这个数据库

create database hello;
use hello;

创建一个

stu_student

数据表

create table stu_test(
 id int primary key auto_increment,
 name varchar(30),
 age int,
 score decimal(4,2)
);

其中第一个id的类型是int,并设置为了

auto_increment

,每次插入数据的时候它都会自增。

name是字符串类型,age是int类型,score分数是浮点类型

decimal(4,2)         表示的范围是 -99.99 ~ 99.99
decimal(4,2)unsigned 表示的范围是 0 ~ 99.99

到这里,前期的准备就完成了

2.接口简单认识

依照注释,简单认识一下mysql库的一些接口

//头文件#include<mysql/mysql.h>//Mysql操作句柄初始化
MYSQL *mysql_init(MYSQL *mysql);
//参数为空则动态申请句柄空间进行初始化//失败返回NULL//连接mysql服务器
MYSQL *mysql_real_connect(MYSQL *mysql,constchar*host,constchar*user,constchar*passwd,constchar*db,unsignedint port,constchar*unix_socket,unsignedlong client_flag);//mysql--初始化完成的句柄//host---连接的mysql服务器的地址//user---连接的服务器的用户名//passwd-连接的服务器的密码//db ----默认选择的数据库名称//port---连接的服务器的端口: 默认0是3306端口//unix_socket---通信管道文件或者socket文件,通常置NULL //client_flag---客户端标志位,通常置0 //返回值:成功返回句柄,失败返回NULL//设置当前客户端的字符集intmysql_set_character_set(MYSQL *mysql,constchar*csname)//mysql--初始化完成的句柄//csname--字符集名称,通常:"utf8" //返回值:成功返回0, 失败返回非0//选择操作的数据库intmysql_select_db(MYSQL *mysql,constchar*db)//mysql--初始化完成的句柄//db-----要切换选择的数据库名称//返回值:成功返回0, 失败返回非0//执行sql语句intmysql_query(MYSQL *mysql,constchar*stmt_str)//mysql--初始化完成的句柄//stmt_str--要执行的sql语句//返回值:成功返回0, 失败返回非0//保存查询结果到本地
MYSQL_RES *mysql_store_result(MYSQL *mysql)//mysql--初始化完成的句柄//返回值:成功返回结果集的指针, 失败返回NULL//获取结果集中的行数与列数uint64_tmysql_num_rows(MYSQL_RES *result);
//result--保存到本地的结果集地址//返回值:结果集中数据的条数;unsignedintmysql_num_fields(MYSQL_RES *result)//result--保存到本地的结果集地址//返回值:结果集中每一条数据的列数;//遍历结果集
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)//result--保存到本地的结果集地址//返回值:实际上是一个char **的指针,将每一条数据做成了字符串指针数组 row[0]-第0列 row[1]-第1列//并且这个接口会保存当前读取结果位置,每次获取的都是下一条数据//释放结果集voidmysql_free_result(MYSQL_RES *result)//result--保存到本地的结果集地址//返回值:void //关闭数据库客户端连接,销毁句柄:voidmysql_close(MYSQL *mysql)//获取mysql接口执行错误原因constchar*mysql_error(MYSQL *mysql)

因为mysql是一个动态库,所以编译的时候,需要加上库名的链接

g++ test.cpp -o test -lmysqlclient

在我的系统下,MySQL的库是在

/usr/lib64

目录下的,所以我不需要额外指定库的路径。如果你的系统该目录下没有

libmysqlclient.so 

,则需要找到库安装的路径,使用

-L

命令指定该路径

g++ test.cpp -o test -L/path/to/mysql/lib -lmysqlclient

3.代码

开始写代码,一步一步认识mysql的各个接口

3.1 连接数据库

因为我的数据库都是默认的环境,所以不需要账户的密码,按如下宏定义一下我们需要操作的数据库信息,方便后续的修改

#include<mysql/mysql.h>#defineHOST"127.0.0.1"#definePORT3306#defineUSER"root"#definePASSWD""#defineDBNAME"hello"

第一步,是用init来初始化一个

MYSQL

的结构体,并用一个指针来接收;

第二步,用

mysql_real_connect

函数来进行数据库的连接,填入我们刚刚的宏定义即可。

第三步,因为在最初配置

mariadb

的环境时,为了更好的支持中文,我们将数据库的字符集设置为了utf8,代码中也需要同步修改,避免因为编码问题产生的数据乱码

最后一步,销毁mysql结构体

int main()
{
    // 连接数据库
    // 初始化
    MYSQL *mysql = mysql_init(nullptr);
    if (mysql == nullptr) // 返回值为空代表init失败
    { 
        cerr << "[ERR] init mysql handle failed!\n"; 
        return -1; 
    }
    // 连接
    cout << "[INFO] connect to " << HOST << ":" << PORT << " " << USER << " " << DBNAME << endl;
    // 第一个参数为输出型参数。返回值为MYSQL的起始地址,如果错误返回NULL
    if (mysql_real_connect(mysql, HOST, USER, PASSWD, DBNAME, PORT, nullptr, 0) == nullptr) 
    {
        cerr << "[ERR] mysql connect error: " << mysql_error(mysql) << endl; 
        return -1;
    }
    // 配置为和数据库同步的utf8字符集
    mysql_set_character_set(mysql, "utf8");
    // 到这里就已经成功了
    cout << "[INFO] mysql database connect success!" << endl; 
    
    // 关闭连接
    mysql_close(mysql); 
    return 0;
}

编译执行,成功链接上了数据库

$ make
g++ test.cpp -o test -lmysqlclient
$ ./test
[INFO] connect to 127.0.0.1:3306 root hello
[INFO] mysql database connect success!

3.2 增加键值

下面要做的,就是给已有表新增一个键值

需要注意的是,mysql的代码操作,实际上也是需要使用sql语句的(这点我觉得好麻烦)

插入语句如下,括号中的键值应该和数据库中表的键值一一对应

insert into stu_test value (null,'牛爷爷',50,64.6);

所以我们要做的,就是写一个函数,将传入的参数合并成一个sql语句,传入mysql进行处理

// 将double转为string
std::string double2string(constdouble& d){
    std::stringstream s_tmp;
    s_tmp << d;  
    std::string s = s_tmp.str();return s;}intadd_key_to_stu(MYSQL *mysql,const std::string& name,int age,double score){// 1.将传入的参数处理为一个完整的sql语句// 因为第一个编号参数,配置的是自增,所以需要传入null
    std::string sql_cmd ="insert into stu_test value (null,'";
    sql_cmd+= name;
    sql_cmd+="',";
    sql_cmd+= std::to_string(age);
    sql_cmd+=",";
    sql_cmd+=double2string(score);
    sql_cmd+=");";
    cout <<"[INFO] "<< sql_cmd << endl;// 2.执行语句int ret =mysql_query(mysql,sql_cmd.c_str());if(ret!=0){
        cerr <<"[ERR] mysql insert error: "<<mysql_error(mysql)<< endl;}return ret;}

如下代码测试

// 添加一个数据add_key_to_stu(mysql,"牛爷爷",50,64.6);add_key_to_stu(mysql,"小图图",5,72.8);

可以看到,成功运行!

$ ./test
[INFO] connect to 127.0.0.1:3306 root hello
[INFO] mysql database connect success!
[INFO] insert into stu_test value (null,'牛爷爷',50,64.6);
[INFO] insert into stu_test value (null,'小图图',5,72.8);

进入mysql命令行,使用如下命令,即可查询到已有的键值

select*from stu_test;

可以看到,处理成功!

+----+-----------+------+-------+
| id | name      | age  | score |
+----+-----------+------+-------+
|  1 | 牛爷爷    |   50 | 64.60 |
|  2 | 小图图    |    5 | 72.80 |
+----+-----------+------+-------+
2 rows in set (0.001 sec)

3.3 修改已有键值

sql语句如下,修改当前数据库中,

stu_test

表中name为牛爷爷的条目的成绩为70

update stu_test set score=70where name='牛爷爷';
// 修改已有学生的成绩intmod_score_in_stu(MYSQL *mysql,const std::string& name,double score){
    std::string sql_cmd ="update ";
    sql_cmd += TABLENAME;
    sql_cmd +=" set score=";
    sql_cmd +=double2string(score);
    sql_cmd +=" where name='";
    sql_cmd += name;
    sql_cmd +="';";
    cout <<"[INFO] "<< sql_cmd << endl;// 2.执行语句int ret =mysql_query(mysql,sql_cmd.c_str());if(ret!=0){
        cerr <<"[ERR] mysql mod_score error: "<<mysql_error(mysql)<< endl;}return ret;}

可以看到,执行成功了之后,牛爷爷的成绩发生了变化

$ ./test
[INFO] connect to 127.0.0.1:3306 root hello
[INFO] mysql database connect success!
[INFO] update stu_test set score=70 where name='牛爷爷';
MariaDB [hello]> select * from stu_test;
+----+-----------+------+-------+
| id | name      | age  | score |
+----+-----------+------+-------+
|  1 | 牛爷爷    |   50 | 64.60 |
|  2 | 小图图    |    5 | 72.80 |
+----+-----------+------+-------+
2 rows in set (0.001 sec)

MariaDB [hello]> select * from stu_test;
+----+-----------+------+-------+
| id | name      | age  | score |
+----+-----------+------+-------+
|  1 | 牛爷爷    |   50 | 70.00 |
|  2 | 小图图    |    5 | 72.80 |
+----+-----------+------+-------+
2 rows in set (0.000 sec)

如果想修改其他键值,也是依照此步骤进行。

在实际场景中,一个数据条目肯定会有一个键值是不变的。比如在我的学生表中,假定每一个学生的名字都不变,我们就可以根据name字段来查找键值,对之进行其他值的修改。

如果真要严肃起来,用名字来查找肯定是不行的,我们应该给每一个学生都生成一个学号或UID,用这个id来进行检索。修改数据之前,都需要知道目标数据的uid值,才能修改。

3.4 删除键值

如下语句,在

test_tb

表中,删除名字为张三的键值

deletefrom test_tb where name='张三';

在删除之前,我又给数据库新增了一个键值

MariaDB [hello]> select * from stu_test;
+----+-----------+------+-------+
| id | name      | age  | score |
+----+-----------+------+-------+
|  1 | 牛爷爷    |   50 | 70.00 |
|  2 | 小图图    |    5 | 72.80 |
|  3 | 大司马    |   42 | 87.30 |
+----+-----------+------+-------+
3 rows in set (0.001 sec)

下面我要用代码,删除掉牛爷爷

// 删除键值(根据名字)intdel_key_in_stu(MYSQL *mysql,const std::string& name){
    std::string sql_cmd ="delete from ";
    sql_cmd += TABLENAME;
    sql_cmd +=" where name='";
    sql_cmd += name;
    sql_cmd +="';";
    cout <<"[INFO] "<< sql_cmd << endl;// 执行语句int ret =mysql_query(mysql,sql_cmd.c_str());if(ret!=0){
        cerr <<"[ERR] mysql mod_score error: "<<mysql_error(mysql)<< endl;}return ret;}
// 删除已有键值
del_key_in_stu(mysql,"牛爷爷");

编译执行

$ ./test
[INFO] connect to 127.0.0.1:3306 root hello
[INFO] mysql database connect success!
[INFO] delete from stu_test where name='牛爷爷';

牛爷爷被删掉了

MariaDB [hello]> select * from stu_test;
+----+-----------+------+-------+
| id | name      | age  | score |
+----+-----------+------+-------+
|  2 | 小图图    |    5 | 72.80 |
|  3 | 大司马    |   42 | 87.30 |
+----+-----------+------+-------+
2 rows in set (0.000 sec)

3.4.1 关于自增的id

此时再插入一个新的键值,可以看到id并么有把空余的1给补上,而是从4开始继续往后增加

MariaDB [hello]> select * from stu_test;
+----+-----------+------+-------+
| id | name      | age  | score |
+----+-----------+------+-------+
|  2 | 小图图    |    5 | 72.80 |
|  3 | 大司马    |   42 | 87.30 |
|  4 | 乐迪      |   32 | 99.00 |
+----+-----------+------+-------+
3 rows in set (0.001 sec)

知道这一点就行

3.5 查询

对于数据库而言,查询也是一个高频操作

select*from  tb  where name=key;

上面的语句,是在数据库表tb中查找键值name为key的的数据

// 返回用户的所有信息,name为空返回所有voidget_all_in_stu(MYSQL *mysql,const std::string& name=""){
    std::string sql_cmd ="select * from ";
    sql_cmd += TABLENAME;if(name.size()!=0){
        sql_cmd +=" where name='";
        sql_cmd += name;
        sql_cmd +="'";}
    sql_cmd +=";";
    cout <<"[INFO] "<< sql_cmd << endl;int ret =mysql_query(mysql,sql_cmd.c_str());if(ret!=0){
        cerr <<"[ERR] mysql query error: "<<mysql_error(mysql)<< endl;return;}// 获取结果
    MYSQL_RES *res =mysql_store_result(mysql);if(res ==nullptr){ 
        cerr <<"[ERR] mysql store_result error: "<<mysql_error(mysql)<< endl;return;}int row =mysql_num_rows(res);// 行int col =mysql_num_fields(res);//列printf("%10s%10s%10s%10s\n","ID","姓名","年龄","成绩");for(int i =0; i < row; i++){ 
        MYSQL_ROW row_data =mysql_fetch_row(res);for(int i =0; i < col; i++){printf("%10s", row_data[i]);}printf("\n");}// 释放结果mysql_free_result(res);}
get_all_in_stu(mysql);

执行结果如下,显示出了表中所有的值

[INFO] connect to 127.0.0.1:3306 root hello
[INFO] mysql database connect success!
[INFO] select * from stu_test;
        ID    姓名    年龄    成绩
         2 小图图         5     72.80
         3 大司马        42     87.30
         4    乐迪        32     99.00

传入特定名字,则只返回改名字所有值

get_all_in_stu(mysql,"乐迪");
[INFO] select * from stu_test where name='乐迪';
        ID    姓名    年龄    成绩
         4    乐迪        32     99.00

这样便实现了查询操作。


3.5.1 模糊匹配

除了使用

name=

,还可以使用

name like %名字%

这条语句进行模糊匹配,即不在乎名字前后的内容,只要有包含名字的数据,就筛选出来。

select*from%s where name like'%牛%';

这样就能将名字里面包含牛的所有数据都筛选出来

3.5.2 查询接口操作注意事项

因为查询的返回值是一个字符串二维数组,并不能通过字段名字获取到对应字段的内容。这要求程序猿知晓这个表中字段的顺序,才能通过下标获取到正确的字段对其进行处理。

因为cpp并不像python那样支持可变变量类型,所以要想筛选出对应类型的数据,还需要我们自行调用对应的函数进行数据的转换。

比如用

atoi

函数将字符串转为整型。

The end

基本的操作到这里就OVER了,后续的其他操作会更新本博客

标签: mysql 数据库 sql

本文转载自: https://blog.csdn.net/muxuen/article/details/131152430
版权归原作者 慕雪华年 所有, 如有侵权,请联系我们删除。

“【MySQL】C/C++代码操作数据库”的评论:

还没有评论