linux C Mysql数据库增删改查(CURD)操作

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 本文的目的主要是接收如何使用mysql提供的C API来实现在linux下的增删改查操作(CURD),没什么技术难点,适用于初学者。

功能介绍

本文的目的主要是接收如何使用mysql提供的C API来实现在linux下的增删改查操作(CURD),没什么技术难点,适用于初学者。主要有以下几个功能:

1.数据的插入

2.数据的查询

3.使用存储过程删除数据 (多条数据库的组合)

4.实现图片的存储和读取操作

这里不对数据库语句和存储过程进行说明,希望读者具有增删改查和存储过程的基本知识。


环境说明

1.实验环境

操作系统: ubuntu16.04

数据库版本:MYSQL5.7

2.环境搭建

(1).安装数据库

命令:sudo apt-get install mysql-server-5.7

(2).安装libmysqlclient开发环境

命令:sudo apt-get install libmysqlclient-dev

说明:如果要使用C语言来操作数据库,这个是必不可少的,头文件mysql.h是和这个libmysqlclient进行绑定的。

(3).安装mysql客户端工具(navicate或者workbench等)

我是在window下操作的,安装navicat

如果是在linux环境下安装workbench: sudo apt-get install mysql-workbench

(3)其他环境

如果是在Windows下使用的是虚拟机环境,最好是要有ssh工具,比如Xshell等。另外还建议使用Samba服务,实现window和linux下的文件共享,具体操作自行百度。

3.准备工作

(1)打开mysql服务:sudo service mysql start

(2)进入到数据库服务: sudo mysql -uroot -p 然后输入密码

(3) 创建admin用户,密码为123456: create user ‘admin’@’%’ identified by ‘123456’; 这里的作用是方便mysql客户端工具连接到mysql服务器。

(4)对admin用户进行授权(为了方便,我们选择授予所有权限,授权后重启mysql服务): grant all on . to ‘admin’@’%’ identified by ‘123456’;

说明:0.0.0.0代表所有地址都可以访问服务器.具体sql权限的问题请自行百度。

注意:(3)和(4)操作都是在mysql命令下操作, 其中第4步,在网上找了很多授权方式都不行,不知道是不是版本原因,另外如果不新建用户,使用root,需要修改配置文件将bind-address修改为0.0.0.0,否则不能进行远程连接。

(4)使用mysql客户端工具进行操作,连接服务器。

2a7d512054a4c7edd0dcff357405fd50_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAYWJjZDU1MjE5MTg2OA==,size_18,color_FFFFFF,t_70,g_se,x_16.png

接下来就使用Navicat客户端进行操作 创建数据库和表语句

CREATE DATABASE IF NOT EXISTS KING_DB;
USE KING_DB;
CREATE TABLE IF NOT EXISTS TBL_USER(
U_ID INT PRIMARY KEY AUTO_INCREMENT,
U_NAME VARCHAR(20),
U_GENDER VARCHAR(8)
);
INSERT TBL_USER(U_NAME, U_GENDER) VALUES('Lee', 'man');
SELECT * FROM TBL_USER;
#MYSQL 5.6默认引入了安全机制,对于删除操作,
#会影响多行的(比如按用户名删除),默认是无法删除的
#SET SQL_SAFE_UPDATES=0; #设置操作模式为非安全
#DELETE FROM TBL_USER WHERE U_NAME = 'King';
#SET SQL_SAFE_UPDATES=1;#设置操作模式为安全模式
DROP PROCEDURE IF EXISTS PROC_DELETE_USER;
#使用存储过程来删除用户
DELIMITER $$  #5.6后引入DELMITER告诉使用什么来结束存储过程,$$可以替换为其他的
 CREATE PROCEDURE PROC_DELETE_USER(IN UNAME VARCHAR(20))
 BEGIN
 SET SQL_SAFE_UPDATES=0; #设置操作模式为非安全
 DELETE FROM TBL_USER WHERE U_NAME = UNAME;
 SET SQL_SAFE_UPDATES=1;#设置操作模式为安全模式
 END$$
#调用存储过程的方式
CALL PROC_DELETE_USER('Lee'); #删除所有用户为Lee的行
alter table TBL_USER add U_IMG BLOB;

上面就是创建好了数据库、表、存储过程。下面就用代码来对数据库进行增删改查的操作。


代码实现

代码说明

里面涉及到的数据库API ,都可以在mysql的帮助文档C API部分找到,关于帮助文档的用法,首先随便输入一个API,然后找到了对应的,然后再使用CTRL+F,进行搜索,就可以看到相应API的使用方法


图片存储和读取

987b539a045da9ad640017b770b67864_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAYWJjZDU1MjE5MTg2OA==,size_20,color_FFFFFF,t_70,g_se,x_16.png

(1)存储图片:首先将图片文件读取到buffer中,然后将buffer存储到数据库中

(2)从数据库中获取图片:首先见图片文件读取到buffer中,然后将buffer写入到文件中


源代码

#include <stdio.h>
#include <string.h>
#include <mysql.h>
#define KING_DB_SERVER_IP  "192.168.179.128"
#define KING_DB_SERVER_PORT  3306
#define KING_DB_USERNAME  "admin"
#define KING_DB_PASSWORD  "123456"
#define KING_DB_DEFAULTDB  "KING_DB"  //数据库名称
#define SQL_INSERT_TBL_USER  "INSERT TBL_USER(U_NAME, U_GENDER) VALUES('King', 'man');"
#define SQL_SELECT_TBL_USER  "SELECT * FROM TBL_USER;"
#define SQL_DELETE_TBL_USER  "CALL PROC_DELETE_USER('King')"
#define SQL_INSERT_IMG_USER  "INSERT TBL_USER(U_NAME, U_GENDER, U_IMG) VALUES('King', 'man', ?);"
#define SQL_SELECT_IMG_USER  "SELECT U_IMG FROM TBL_USER WHERE U_NAME='King';"
#define FILE_IMAGE_LENGTH  (64*1024)  //存放图片的buffer
// C U R D --> 
// 
int king_mysql_select(MYSQL *handle) { //
  // mysql_real_query --> sql
  if (mysql_real_query(handle, SQL_SELECT_TBL_USER, strlen(SQL_SELECT_TBL_USER))) {
  printf("mysql_real_query : %s\n", mysql_error(handle));
  return -1;
  }
  // store --> 
  MYSQL_RES *res = mysql_store_result(handle);//存放结果集
  if (res == NULL) {
  printf("mysql_store_result : %s\n", mysql_error(handle));
  return -2;
  }
  // rows / fields
  int rows = mysql_num_rows(res);//结果集的行数
  printf("rows: %d\n", rows);
  int fields = mysql_num_fields(res);//结果集的列数
  printf("fields: %d\n", fields);
  // fetch
  MYSQL_ROW row;//1行数据的“类型安全”表示。
  while ((row = mysql_fetch_row(res))) {//从结果集中获取下一行,如果没有行了,则返回NULL
  int i = 0;
  for (i = 0;i < fields;i ++) {
    printf("%s\t", row[i]);//row[0]-row[fields-1]为某一行的所有数据项
  }
  printf("\n");
  }
  //释放由mysql_store_result()、mysql_use_result()、mysql_list_dbs()等为结果集分配的内存。
  mysql_free_result(res);
  return 0;
}
// filename[in]: path + file name 要读取的文件名
// buffer[out]: store image data 存储文件的缓冲
int read_image(char *filename, char *buffer) {
  if (filename == NULL || buffer == NULL) return -1;
  FILE *fp = fopen(filename, "rb"); //
  if (fp == NULL) {
  printf("fopen failed\n");
  return -2;
  }
  // file size
  fseek(fp, 0, SEEK_END);
  int length = ftell(fp); // file size
  fseek(fp, 0, SEEK_SET);
  int size = fread(buffer, 1, length, fp);
  if (size != length) {
  printf("fread failed: %d\n", size);
  return -3;
  }
  fclose(fp);
  return size;
}
// filename : 要写入的文件 
// buffer : 读入的缓冲(图片数据已经存到该缓冲中)
// length : 要读入的长度
int write_image(char *filename, char *buffer, int length) {
  if (filename == NULL || buffer == NULL || length <= 0) return -1;
  FILE *fp = fopen(filename, "wb+"); //
  if (fp == NULL) {
  printf("fopen failed\n");
  return -2;
  }
  int size = fwrite(buffer, 1, length, fp);//将buffer的数据写入到文件中
  if (size != length) {
  printf("fwrite failed: %d\n", size);
  return -3;
  }
  fclose(fp);
  return size;
}
//buffer的数据存入到mysql中
//buffer:要存取到数据库的buffer数据
//length:要存入的长度 
int mysql_write(MYSQL *handle, char *buffer, int length) {
  if (handle == NULL || buffer == NULL || length <= 0) return -1;
    //MYSQL_STMT:该结构用于有预处理语句(带?的SQL,这里SQL是一个占位符,代表一个参数,
  //这个参数可能无法直接像varchar,int等可以表示出来,比如BLOG数据类型,需要使用MYSQL_BIND来绑定其参数)的SQL
  MYSQL_STMT *stmt = mysql_stmt_init(handle);
  //
  int ret = mysql_stmt_prepare(stmt, SQL_INSERT_IMG_USER, strlen(SQL_INSERT_IMG_USER));
  if (ret) {
  printf("mysql_stmt_prepare : %s\n", mysql_error(handle));
  return -2;
  }
  //MYSQL_BIND结构用于语句输入(发送给服务器的数据值)和输出(从服务器返回的结果值)
  MYSQL_BIND param = {0}; //语句输入(绑定输入参数)
  param.buffer_type  = MYSQL_TYPE_LONG_BLOB;//指明了与语句参数捆绑的值类型
  param.buffer = NULL;//指向存储语句参数数据值的缓冲的指针
  param.is_null = 0;//如果数据值总是NOT NULL,设置is_null = (my_bool*) 0。
  param.length = NULL;
  ret = mysql_stmt_bind_param(stmt, &param);//将参数和预处理语句结构进行绑定
  if (ret) {
  printf("mysql_stmt_bind_param : %s\n", mysql_error(handle));
  return -3;
  }
  //允许应用程序分段地(分块)将参数数据发送到服务器。可以多次调用该函数,
  //以便发送关于某一列的字符或二进制数据的不同部分,列必须是TEXT或BLOB数据类型之一。
  ret = mysql_stmt_send_long_data(stmt, 0, buffer, length);
  if (ret) {
  printf("mysql_stmt_send_long_data : %s\n", mysql_error(handle));
  return -4;
  }
  ret = mysql_stmt_execute(stmt);//执行与语句句柄相关的预处理查询。
  if (ret) {
  printf("mysql_stmt_execute : %s\n", mysql_error(handle));
  return -5;
  }
  ret = mysql_stmt_close(stmt);//释放预处理语句使用的内存。
  if (ret) {
  printf("mysql_stmt_close : %s\n", mysql_error(handle));
  return -6;
  }
  return ret;
}
//从数据库中将图片数据读入到buffer中
//buffer:存放数据的buffer
//buffer的预分配长度
int mysql_read(MYSQL *handle, char *buffer, int length) {
  if (handle == NULL || buffer == NULL || length <= 0) return -1;
  MYSQL_STMT *stmt = mysql_stmt_init(handle);
  int ret = mysql_stmt_prepare(stmt, SQL_SELECT_IMG_USER, strlen(SQL_SELECT_IMG_USER));
  if (ret) {
  printf("mysql_stmt_prepare : %s\n", mysql_error(handle));
  return -2;
  }
  //result与mysql_stmt_bind_result()一起使用,用于绑定结果缓冲区,以便用于with mysql_stmt_fetch()以获取行。
  MYSQL_BIND result = {0};//结果参数
  result.buffer_type  = MYSQL_TYPE_LONG_BLOB;//指明了你希望从结果缓冲收到的值类型。
  unsigned long total_length = 0;//存放结果集的总长度(注意,这里是一行的总长度,后面mysql_stmt_fetch先得到一行的结果集,然后在对一行数据进行操作)
  指向unsigned long变量的指针,该变量指明了存储在*buffer中数据的实际字节数。
  result.length = &total_length;
    //将结果集中的列与数据缓冲和长度缓冲关联(绑定)起来。
  ret = mysql_stmt_bind_result(stmt, &result);
  if (ret) {
  printf("mysql_stmt_bind_result : %s\n", mysql_error(handle));
  return -3;
  }
  ret = mysql_stmt_execute(stmt);//执行与语句句柄相关的预处理查询。
  if (ret) {
  printf("mysql_stmt_execute : %s\n", mysql_error(handle));
  return -4;
  }
  //对于成功生成结果集的所有语句(SELECT、SHOW、DESCRIBE、EXPLAIN),
  //而且仅当你打算对客户端的全部结果集进行缓冲处理时,
  //必须调用mysql_stmt_store_result(),以便后续的mysql_stmt_fetch()调用能返回缓冲数据。
  ret = mysql_stmt_store_result(stmt);//将结果存入到缓冲中
  if (ret) {
  printf("mysql_stmt_store_result : %s\n", mysql_error(handle));
  return -5;
  }
  //注意,如果如果有多个数据被查询出来,得到的是最后一张图片的数据
  while (1) { 
  ret = mysql_stmt_fetch(stmt);//返回结果集中的下一行。
  // 出现错误或者数据读取完成时退出
  if (ret != 0 && ret != MYSQL_DATA_TRUNCATED) break; 
  int start = 0;//用于存放每一行距离缓冲的开始值
  //循环得到一行图片的数据信息
  while (start < (int)total_length) {
    //buffer和result.buffer公用一个空间,
    //下一行数据好像会覆盖上一次的数据,
    //也就是buffer最终得到的是最后一张图片的数据,
    //大家可以自己测试以下,比如一个名字有2行数据,
    //但是不是同一张图,看得到的是不是就是最后一行的数据
    //由于每次start变量都在增加,因此指针的值也在增加,
    //result.buffer每次也在增加
    //最终的buffer值会得到整个图片的值
    result.buffer = buffer + start;
    //指明了每次可保存在缓冲区内的最大数据(这里设置为1字节,代表每次读取1个字节到buffer中)
    result.buffer_length = 1;
    //从当前结果集行获取1列,0-代表第一列,start是数据的偏移量,
    //将从该处开始检索数据,&result提供了应将数据置于其中的缓冲.
    mysql_stmt_fetch_column(stmt, &result, 0, start);
    start += result.buffer_length;
  }
  }
  mysql_stmt_close(stmt);
  return total_length;//返回最后一张图片的长度
}
int main() {
  MYSQL mysql;
  if (NULL == mysql_init(&mysql)) {
  printf("mysql_init : %s\n", mysql_error(&mysql));
  return -1;
  }
  if (!mysql_real_connect(&mysql, KING_DB_SERVER_IP, KING_DB_USERNAME, KING_DB_PASSWORD, 
  KING_DB_DEFAULTDB, KING_DB_SERVER_PORT, NULL, 0)) {
  printf("mysql_real_connect : %s\n", mysql_error(&mysql));
  goto Exit;
  }
  // mysql --> insert 
  printf("case : mysql --> insert \n");
#if 1
  if (mysql_real_query(&mysql, SQL_INSERT_TBL_USER, strlen(SQL_INSERT_TBL_USER))) {
  printf("mysql_real_query : %s\n", mysql_error(&mysql));
  goto Exit;
  }
#endif
  king_mysql_select(&mysql);
  // mysql --> delete 
#if 1
    printf("case : mysql --> delete \n");
  if (mysql_real_query(&mysql, SQL_DELETE_TBL_USER, strlen(SQL_DELETE_TBL_USER))) {
  printf("mysql_real_query : %s\n", mysql_error(&mysql));
  goto Exit;
  }
#endif
  king_mysql_select(&mysql);
  printf("case : mysql --> read image and write mysql\n");  
  char buffer[FILE_IMAGE_LENGTH] = {0};
  int length = read_image("0voice.jpg", buffer);//要保证该图片存在
  if (length < 0) goto Exit;
  mysql_write(&mysql, buffer, length); /// 
  printf("case : mysql --> read mysql and write image\n");  
  memset(buffer, 0, FILE_IMAGE_LENGTH);
  length = mysql_read(&mysql, buffer, FILE_IMAGE_LENGTH);
  write_image("a.jpg", buffer, length);
Exit:
  mysql_close(&mysql);
  return 0;
}

代码运行

命令:gcc -o mysql mysql.c -I /usr/include/mysql/ -lmysqlclient

注意:要保证图片存在,否则无法对图片进行操作。

代码来源

腾讯课堂-零声学院king老师

工具准备

1 .Navicat或者workbench客户端操作工具

2. SSH连接工具,比如Xshell等(虚拟机环境)

3. mysql参考手册(使用C操作数据库的相关API的教程)

4. 另外window环境还建议搭建Samba服务。

PS

如果有需要工具或者其他错误问题的朋友,可以给我留言。


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
13天前
|
关系型数据库 MySQL Linux
MySQL数据库下载安装教程(Windows&Linux)
本文档详细介绍了MySQL的安装步骤,包括安装前的准备工作、下载安装包、Windows和Linux系统下的具体安装流程,以及如何配置MySQL服务、设置环境变量、启动服务和连接数据库等关键操作。
|
19天前
|
数据库连接 Linux Shell
Linux下ODBC与 南大通用GBase 8s数据库的无缝连接配置指南
本文详细介绍在Linux系统下配置GBase 8s数据库ODBC的过程,涵盖环境变量设置、ODBC配置文件编辑及连接测试等步骤。首先配置数据库环境变量如GBASEDBTDIR、PATH等,接着修改odbcinst.ini和odbc.ini文件,指定驱动路径、数据库名称等信息,最后通过catalog.c工具或isql命令验证ODBC连接是否成功。
|
1月前
|
关系型数据库 MySQL Linux
Linux环境下MySQL数据库自动定时备份实践
数据库备份是确保数据安全的重要措施。在Linux环境下,实现MySQL数据库的自动定时备份可以通过多种方式完成。本文将介绍如何使用`cron`定时任务和`mysqldump`工具来实现MySQL数据库的每日自动备份。
79 3
|
1月前
|
监控 关系型数据库 MySQL
Linux环境下MySQL数据库自动定时备份策略
在Linux环境下,MySQL数据库的自动定时备份是确保数据安全和可靠性的重要措施。通过设置定时任务,我们可以每天自动执行数据库备份,从而减少人为错误和提高数据恢复的效率。本文将详细介绍如何在Linux下实现MySQL数据库的自动定时备份。
39 3
|
1月前
|
关系型数据库 MySQL Linux
Linux系统如何设置自启动服务在MySQL数据库启动后执行?
【10月更文挑战第25天】Linux系统如何设置自启动服务在MySQL数据库启动后执行?
104 3
|
8天前
|
关系型数据库 MySQL 数据库
Python处理数据库:MySQL与SQLite详解 | python小知识
本文详细介绍了如何使用Python操作MySQL和SQLite数据库,包括安装必要的库、连接数据库、执行增删改查等基本操作,适合初学者快速上手。
69 15
|
1天前
|
SQL 关系型数据库 MySQL
数据库数据恢复—Mysql数据库表记录丢失的数据恢复方案
Mysql数据库故障: Mysql数据库表记录丢失。 Mysql数据库故障表现: 1、Mysql数据库表中无任何数据或只有部分数据。 2、客户端无法查询到完整的信息。
|
8天前
|
关系型数据库 MySQL 数据库
数据库数据恢复—MYSQL数据库文件损坏的数据恢复案例
mysql数据库文件ibdata1、MYI、MYD损坏。 故障表现:1、数据库无法进行查询等操作;2、使用mysqlcheck和myisamchk无法修复数据库。
|
13天前
|
SQL 关系型数据库 MySQL
MySQL导入.sql文件后数据库乱码问题
本文分析了导入.sql文件后数据库备注出现乱码的原因,包括字符集不匹配、备注内容编码问题及MySQL版本或配置问题,并提供了详细的解决步骤,如检查和统一字符集设置、修改客户端连接方式、检查MySQL配置等,确保导入过程顺利。
|
20天前
|
关系型数据库 MySQL 数据库
GBase 数据库如何像MYSQL一样存放多行数据
GBase 数据库如何像MYSQL一样存放多行数据