使用C语言+MySQL存储过程实现数据库删除功能

一、背景简介

在 C 语言程序中执行 SQL 指令通常是通过 mysql_real_query() 等 API 完成的,但当 SQL 指令较复杂或跨多行时(如包含控制结构),直接用宏定义变得不现实。

尤其在如下场景中:

#define SQL_DELETE_TBL_USER "CALL PROC_DELETE_USER('charon')"

我们希望宏中包含多行 SQL,如:

SET SQL_SAFE_UPDATES=0;
DELETE FROM TBL_USER WHERE U_NAME='charon';
SET SQL_SAFE_UPDATES=1;

但 C 语言的宏不支持多行字符串中的控制逻辑或换行语法,因此使用 MySQL 存储过程(Stored Procedure) 来封装删除逻辑成为了优雅的解决方案。

二、创建MySQL存储过程

打开 MySQL Workbench,依次执行以下语句创建并使用存储过程:

-- 如果存储过程已存在,则先删除,避免重复创建时报错
DROP PROCEDURE IF EXISTS PROC_DELETE_USER;

-- 修改语句结束符为 $$,以支持过程体中包含分号的语句
DELIMITER $$

-- 创建名为 PROC_DELETE_USER 的存储过程,接受一个输入参数 UNAME
CREATE PROCEDURE PROC_DELETE_USER(IN UNAME VARCHAR(32))
BEGIN
    -- 关闭 SQL 安全更新模式,允许在没有主键或 WHERE 主键条件的情况下进行删除
    SET SQL_SAFE_UPDATES = 0;

    -- 删除用户表中用户名等于传入参数的记录
    DELETE FROM TBL_USER WHERE U_NAME = UNAME;

    -- 恢复 SQL 安全更新模式,防止误删数据
    SET SQL_SAFE_UPDATES = 1;
END$$

-- 恢复默认语句结束符 ;
DELIMITER ;

-- 调用该存储过程,删除用户名为 'mianqian' 的记录
CALL PROC_DELETE_USER('mianqian');

三、C语言代码:增查删完整流程

你的 C 端代码结构清晰,分三步操作:

  1. 插入测试数据

  2. 查询展示当前用户表

  3. 调用 CALL PROC_DELETE_USER('xxx') 删除指定用户

  4. 再次查询结果,验证是否删除成功

代码核心部分如下

#define SQL_DELETE_TBL_USER "CALL PROC_DELETE_USER('charon')"
mysql_real_query(&mysql, SQL_DELETE_TBL_USER, strlen(SQL_DELETE_TBL_USER));

查询函数 king_mysql_select() 能完整遍历并打印结果集,便于验证效果。

四、完整代码示例

#include <mysql.h>
#include <string.h>
#include <stdio.h>

#define KING_DB_SERVER_IP   "10.0.0.129"
#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_GENGDER) VALUES('charon','man');"
#define SQL_SELECT_TBL_USER     "SELECT * FROM TBL_USER;"

#define SQL_DELETE_TBL_USER     "CALL PROC_DELETE_USER('charon')"

int king_mysql_select(MYSQL *mysql) {
    if(mysql_real_query(mysql,SQL_SELECT_TBL_USER,strlen(SQL_SELECT_TBL_USER))){
        printf("mysql_real_query : %s\n", mysql_error(mysql));
        return -1;
    }

    MYSQL_RES *res = mysql_store_result(mysql);
    if(res == NULL){
        printf("mysql_store_result : %s\n",mysql_error(mysql));
        return -2;
    }

    int rows = mysql_num_rows(res);
    printf("rows: %d\n",rows);

    int fields = mysql_num_fields(res);
    printf("fields: %d\n",fields);

    MYSQL_ROW row;
    while((row = mysql_fetch_row(res))){
        for(int i = 0; i < fields; i++){
            printf("%s\t",row[i]);
        }
        printf("\n");
    }

    mysql_free_result(res);
    return 0;
}

int main() {
    MYSQL mysql;
    if(NULL == mysql_init(&mysql)){
        printf("mysql_init : %s\n",mysql_error(&mysql));
        return -1;
    }

    //返回非0成功
    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));
        return -2;
    }

    printf("case : mysql --> select\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));
        return -3;
    }
#endif
    king_mysql_select(&mysql);

    printf("case : mysql --> delete\n");

#if 1
    if(mysql_real_query(&mysql,SQL_DELETE_TBL_USER,strlen(SQL_DELETE_TBL_USER))){
        printf("mysql_real_query : %s\n", mysql_error(&mysql));
        return -4;
    }
#endif
    king_mysql_select(&mysql);

    mysql_close(&mysql);
    return 0;
}

五、一些注意点与总结

为什么用存储过程?

  • 避免 SQL 宏定义中出现换行和复杂控制逻辑导致编译失败或语义错误。

  • 逻辑集中封装,便于复用和维护。

  • 动态传参删除更安全、灵活。

遇到的坑

  • 存储过程未删除成功,原因可能是拼写错误或 PROC_DELETE_USER 已存在未更新。

  • 使用 DROP PROCEDURE IF EXISTS 可避免重复定义报错。

  • SQL_SAFE_UPDATES=0 必须在过程内设置,否则会因没有主键条件而删除失败。

六、运行效果展示

charon@charon:~/20_share/05_mysql$ gcc -o mysql MySQL.c -I /usr/include/mysql/ -lmysqlclient
charon@charon:~/20_share/05_mysql$ ./mysql 
case : mysql --> select
rows: 3
fields: 3
7	King	man	
8	charon	man	
9	charon	man	
case : mysql --> delete
rows: 1
fields: 3
7	King	man	

验证 charon 成功删除。

0voice · GitHub

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值