简单尝试使用 c 语言的库对 mysql 的数据进行增删改查。
1.新增数据库和表 
刚开始数据库没有设定密码和用户,直接用root用户登录
创建一个hello数据库,并进入这个数据库
1 2 create database hello; use hello; 
创建一个stu_student数据表
1 2 3 4 5 6 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分数是浮点类型
1 2 decimal(4,2)         表示的范围是 -99.99 ~ 99.99 decimal(4,2)unsigned 表示的范围是 0 ~ 99.99 
到这里,前期的准备就完成了
2.接口简单认识 
依照注释,简单认识一下mysql库的一些接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 #include  <mysql/mysql.h>  MYSQL *mysql_init (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  client_flag) ; int  mysql_set_character_set (MYSQL *mysql, const  char  *csname)       int  mysql_select_db (MYSQL *mysql, const  char  *db)       int  mysql_query (MYSQL *mysql, const  char  *stmt_str)       MYSQL_RES *mysql_store_result (MYSQL *mysql)        uint64_t  mysql_num_rows (MYSQL_RES *result) ;unsigned  int  mysql_num_fields (MYSQL_RES *result)       MYSQL_ROW mysql_fetch_row (MYSQL_RES *result)   void  mysql_free_result (MYSQL_RES *result)    void  mysql_close (MYSQL *mysql)    const  char  *mysql_error (MYSQL *mysql) 
因为mysql是一个动态库,所以编译的时候,需要加上库名的链接
1 g++ test.cpp -o test -lmysqlclient 
在我的系统下,MySQL的库是在/usr/lib64目录下的,所以我不需要额外指定库的路径。如果你的系统该目录下没有libmysqlclient.so ,则需要找到库安装的路径,使用-L命令指定该路径
1 g++ test.cpp -o test -L/path/to/mysql/lib -lmysqlclient 
3.代码 
开始写代码,一步一步认识mysql的各个接口
3.1 连接数据库 
因为我的数据库都是默认的环境,所以不需要账户的密码,按如下宏定义一下我们需要操作的数据库信息,方便后续的修改
1 2 3 4 5 6 #include  <mysql/mysql.h>  #define  HOST "127.0.0.1"  #define  PORT 3306 #define  USER "root"  #define  PASSWD ""  #define  DBNAME "hello"  
第一步,是用init来初始化一个MYSQL的结构体,并用一个指针来接收;
第二步,用mysql_real_connect函数来进行数据库的连接,填入我们刚刚的宏定义即可。
第三步,因为在最初配置mariadb的环境时,为了更好的支持中文,我们将数据库的字符集设置为了utf8,代码中也需要同步修改,避免因为编码问题产生的数据乱码
最后一步,销毁mysql结构体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 int  main ()               MYSQL *mysql = mysql_init (nullptr );     if  (mysql == nullptr )      {          cerr << "[ERR] init mysql handle failed!\n" ;          return  -1 ;      }          cout << "[INFO] connect to "  << HOST << ":"  << PORT << " "  << USER << " "  << DBNAME << endl;          if  (mysql_real_connect (mysql, HOST, USER, PASSWD, DBNAME, PORT, nullptr , 0 ) == nullptr )      {         cerr << "[ERR] mysql connect error: "  << mysql_error (mysql) << endl;          return  -1 ;     }          mysql_set_character_set (mysql, "utf8" );          cout << "[INFO] mysql database connect success!"  << endl;                mysql_close (mysql);      return  0 ; } 
编译执行,成功链接上了数据库
1 2 3 4 5 $ 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语句的(这点我觉得好麻烦)
插入语句如下,括号中的键值应该和数据库中表的键值一一对应
1 insert into stu_test value (null,'牛爷爷',50,64.6); 
所以我们要做的,就是写一个函数,将传入的参数合并成一个sql语句,传入mysql进行处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 std::string double2string (const  double & d)      std::stringstream s_tmp;     s_tmp << d;       std::string s = s_tmp.str ();     return  s; } int  add_key_to_stu (MYSQL *mysql,const  std::string& name,int  age,double  score)               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;               int  ret = mysql_query (mysql,sql_cmd.c_str ());     if (ret!=0 )     {         cerr << "[ERR] mysql insert error: "  << mysql_error (mysql) << endl;      }     return  ret; } 
如下代码测试
1 2 3 add_key_to_stu(mysql,"牛爷爷" ,50 ,64.6 ); add_key_to_stu(mysql,"小图图" ,5 ,72.8 ); 
可以看到,成功运行!
1 2 3 4 5 $ ./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命令行,使用如下命令,即可查询到已有的键值
可以看到,处理成功!
1 2 3 4 5 6 7 +----+-----------+------+-------+ | 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
1 update  stu_test set  score= 70  where  name= '牛爷爷' ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int  mod_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;               int  ret = mysql_query (mysql,sql_cmd.c_str ());     if (ret!=0 )     {         cerr << "[ERR] mysql mod_score error: "  << mysql_error (mysql) << endl;      }     return  ret; } 
可以看到,执行成功了之后,牛爷爷的成绩发生了变化
1 2 3 4 $ ./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='牛爷爷'; 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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表中,删除名字为张三的键值
1 delete  from  test_tb where  name= '张三' ;
在删除之前,我又给数据库新增了一个键值
1 2 3 4 5 6 7 8 9 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) 
下面我要用代码,删除掉牛爷爷
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int  del_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; } 
1 2 // 删除已有键值 del_key_in_stu(mysql,"牛爷爷"); 
编译执行
1 2 3 4 $ ./test [INFO] connect to 127.0.0.1:3306 root hello [INFO] mysql database connect success! [INFO] delete from stu_test where name='牛爷爷'; 
牛爷爷被删掉了
1 2 3 4 5 6 7 8 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开始继续往后增加
1 2 3 4 5 6 7 8 9 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 查询 
对于数据库而言,查询也是一个高频操作
1 select  *  from   tb  where  name= key;
上面的语句,是在数据库表tb中查找键值name为key的的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 void  get_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); } 
执行结果如下,显示出了表中所有的值
1 2 3 4 5 6 7 [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 
传入特定名字,则只返回改名字所有值
1 get_all_in_stu(mysql,"乐迪"); 
1 2 3 [INFO] select * from stu_test where name='乐迪';         ID    姓名    年龄    成绩          4    乐迪        32     99.00 
这样便实现了查询操作。
3.5.1 模糊匹配 
除了使用name=,还可以使用name like %名字%这条语句进行模糊匹配,即不在乎名字前后的内容,只要有包含名字的数据,就筛选出来。
1 select  *  from  % s where  name like  '%牛%' ;
这样就能将名字里面包含牛的所有数据都筛选出来
3.5.2 查询接口操作注意事项 
因为查询的返回值是一个字符串二维数组,并不能通过字段名字获取到对应字段的内容。这要求程序猿知晓这个表中字段的顺序,才能通过下标获取到正确的字段对其进行处理。
因为cpp并不像python那样支持可变变量类型,所以要想筛选出对应类型的数据,还需要我们自行调用对应的函数进行数据的转换。
比如用atoi函数将字符串转为整型。
The end 
基本的操作到这里就OVER了,后续的其他操作会更新本博客;
详细的用例可以看我的视频点播项目 内部中和mysql相关的代码