Linux下访问数据库

2023-11-02

Linux下访问数据库

         声明:本文只简单描述Linux系统下访问mysql数据库的步骤,关于连接上数据库之后的简单的对于数据库的增删改查等操作只是稍微提及,关于增删改查的语句书写,本文不再讲述。

         一般来说,访问数据库有如下几个步骤:

         1.初始化mysql环境

         2.连接数据库

         3.执行sql语句

         4.获取查询结果

         5.显示结果

         6.关闭数据库

         7.释放mysql环境

         针对以上7个步骤,接下来重点描述以下者7个步骤中所需要做的工作和所使用到的函数。

1.初始化mysql环境

         作为连接数据库前的准备工作,这个步骤要做的事情其实还是很多的。首先需要创建MYSQL变量,用来存储与连接有关的数据信息。其结构体的结构非常复杂,不需要过多的理解。在实际使用时有着其固定的使用方法,只需记住就行。

typedef struct st_mysql 
{
    NET net;           
    gptr connector_fd; 
    char *host, *user,*passwd,*unix_socket,*server_version, *host_info,*info,*db;
    unsigned int port,client_flag,server_capabilities;
    unsigned int protocol_version;
    unsigned int field_count;
    unsigned int server_status;
    unsigned long thread_id;      
    my_ulonglong affected_rows;
    my_ulonglong insert_id;       
    my_ulonglong extra_info;              
    unsigned long packet_length;
    enum mysql_status status;
    MYSQL_FIELD *fields;
    MEM_ROOT field_alloc;
    my_bool free_me;       
    my_bool reconnect;    
    struct st_mysql_options options;
    char scramble_buff[9];
    struct charset_info_st *charset;
    unsigned int server_language;
}MYSQL;

         除此之外,此阶段还有两个函数也至关重要,mysql_init()函数和mysql_library_init()函数。

MYSQL *mysql_init(MYSQL *mysql);

功能:用来初始化一个连接句柄

若函数成功执行,则返回一个MYSQL类型的指针,失败则返回NULL。

int mysql_library_init(int argc,char **argv,char **groups);

功能:用来初始化mysql库

关于这两个函数的参数含义此处不做解释,因为本鸟也不知道,唯一知道的就是这么用就对了,实际使用时给三个参数赋值为0,NULL,NULL,具体使用方法会在最后的案例中提及。

还有一个与mysql_library_init()函数相对应的函数mysql_library_end(),用来关闭服务器端数据库。这两个函数必须放在一起使用,先初始化,最后再关闭数据库,如果只初始化不关闭,那么之前申请的一块内存将会一直存在,容易导致内存泄漏。

2.连接数据库

         连接数据库部分涉及到两个函数,分别是mysql_real_connect()函数和mysql_select_db()函数。

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变量

host:MYSQL服务器的地址

user:登陆用户名

passwd:登陆密码

db:要连接的数据库

port:MYSQL服务器的TCP服务端口

unix_socket:unix连接方式,为NULL时表示不使用socket或管道机制

clientflag:mysql运行为ODBC数据库的标记,一般取0

返回值:成功,返回*mysql指针,失败,返回NULL

         此函数的参数较多,实际使用时不会给每个参数都赋值的,只需要记住最常被赋值的几个参数即可。

int mysql_select_db(MYSQL *mysql,const char *db);

功能:使得由db指定的数据库成为由mysql指定的连接上的默认数据库

返回值:成功,返回0;失败,返回一个非0值。

错误代码:

CR_COMMANDS_OUT_OF_SYNC:以不恰当的顺序执行了命令

CR_SERVER_GONE_ERROR:mysql服务器不可用

CR_SERVER_LOST:在查询过程中与服务器的连接丢失

CR_UNKNOWN_ERROR:出现未知错误

3.执行sql语句

         当数据库连接成功之后就可以对数据库中的数据进行增删改查等操作了,这些增删改查的语句本鸟不再书写,相信大家都会吧。但是,这些语句并不是独自出现的,而是把它存储在一个缓冲区里,作为函数参数使用,此函数为:

int mysql_query(MYSQL *mysql,const char *q);

功能:执行sql语句

参数:第一个参数为mysql结构体,第二个参数为操作命令。

         还有一个可用来执行sql语句的函数:

int mysql_real_query(MYSQL *mysql,const char *query,unsigned long length);

功能:进行数据库查询。执行由query指向的sql查询,正常情况下,字符串必须包含一条sql语句,而且不应该为语句添加终结分号。

参数说明:

mysql:MYSQL变量

query:查询语句

length:查询语句的长度

         以上两个函数都是用来进行数据库查询的函数。不同之处在于,对于包含二进制数据的查询,必须使用mysql_real_query()函数,这是因为  二进制数据可能会包含‘\0’字符,同时,mysql_real_query()函数执行速度快,这是因为此函数不会在查询字符串上调用strlen()函数。

         执行sql语句后,我们通过调用mysql_store_result()或mysql_use_result()函数返回的MYSQL_RES变量获取查询结果数据。

MYSQL_RES *mysql_store_result(MYSQL *mysql);
MYSQL_RES *mysql_use_result(MYSQL *mysql);

这两个函数分别代表了获取查询结果的两种方式。

         第一种,调用mysql_store_result()函数将从mysql服务器查询的所有数据都存储到客户端,然后读取;

         第二种,调用mysql_use_result()初始化检索,以便于后面一行一行的读取结果集,而它本身并没有从服务器读取任何数据,这种方式较之第一种速度更快且所需内存更少,但它会绑定服务器,阻止其他线程更新任何表,而且必须重复执行mysql_fetch_row()读取数据,直至返回NULL,否则未读取的行会在下一次查询时作为结果的一部分返回,故经常我们使用mysql_store_result()。

4.获取查询结果

         我们把执行完sql语句的返回的结果称为结果集,其用一个MYSQL_RES结构体来存储。本部分的主要内容就是从返回的结果集里获取查询结果。

typedef struct st_mysql_res 
{
    my_ulonglong row_count;
    unsigned int field_count, current_field;
    MYSQL_FIELD *fields;
    MYSQL_DATA *data;
    MYSQL_ROWS *data_cursor;
    MEM_ROOT field_alloc;
    MYSQL_ROW row;           
    MYSQL_ROW current_row;   
    unsigned long *lengths; 
    MYSQL *handle;      
    my_bool eof;         
}MYSQL_RES;

         这样的结构体着实令本鸟头大。

         我们执行sql语句后的结果就存储在这样一个结构体中,但是我们要想从这个结构体中获取到,或者说提取出我们需要的信息,则就必须使用MYSQL_FIELDMYSQL_ROWS结构体来获取。这个结构体包含着结果集中的字段名、字段类型、字段大小等信息,可以通过重复调用mysql_fetch_fields()函数来获得所有字段的信息,即列信息或列数据。

typedef struct st_mysql_field 
{
    char *name;                  
    char *table;                 
    char *def;                    
    enum enum_field_types type;  
    unsigned int length;         
    unsigned int max_length;    
    unsigned int flags;         
    unsigned int decimals;  
} MYSQL_FIELD;
MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res);

功能:读取结果集字段

         与之对应的是MYSQL_ROWS结构体里的mysql_fetch_row()函数,此函数用来获得结果集中的行信息。

MYSQL_ROW *mysql_fetch_row(MYSQL_RES *res);

功能:读取结果集数据

返回值:该函数返回MYSQL_ROW型的变量,即字符串数组,假设其为row,则row[i]为第i个字段的值,当到结果集尾部时,此函数返回NULL。

         刚才说到mysql_fetch_row()函数是用来获取数据集中的数据信息,它只能一行一行的来获取,所以还得有个函数用来统计结果集中的行数。同样的,也得用一个函数来获取结果集中的字段的数量。

unsigned int mysql_num_fields(MYSQL_RES *res);

功能:获取结果集中字段的数量

unsigned int mysql_num_rows(MYSQL_RES *res);

功能:获取结果集中行数

         结果集使用完毕后,还需释放掉结果集,避免内存泄漏。

void mysql_free_result(MYSQL_RES *res);

5.关闭数据库

         不需要继续查询mysql数据库时,应及时关闭数据库连接。

void mysql_close(MYSQL *sock);

         sock为连接函数返回的变量。

6.释放mysql环境

         在初始化阶段中提到了一个与mysql_library_init()函数相对应的函数mysql_library_end(),此函数用来及时释放mysql环境,来终止使用mysql数据库。

案例:MysqlDemo.c

         本案例主要是通过远程访问数据库来对数据库里的数据信息进行增删改查等操作。在正式编码之前,我们首先需要直到关于本案例所要用到的数据库的基本信息。本案例所使用的数据库为StaffDB,该数据库里有3张表,分别为Department(部门)、Work(职务)、Staff(员工信息),每张表的结构和数据如下所示:

Department(部门):

Work(职务):

Staff(员工):

         这3张表的截图都是在Windows系统下所截取的,我们就是要通过案例来对这些数据加以操作。

MysqlDemo.c

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

//查询
int Select_sql(MYSQL *p_sock)
{
    //声明缓冲区并初始化
    char buffer[1024]={0};
    memset(buffer,0x00,1024);
    snprintf(buffer,sizeof(buffer),"%s","select * from Department");
    //执行sql语句
    int ret = mysql_query(p_sock,buffer);
    if(ret != 0)
    {
        printf("查询错误:%s\n",mysql_error(p_sock));
        return -1;
    }
    
    //结果集
    MYSQL_RES *res;
    //数据行
    MYSQL_ROW row;
    //记录结果的行数
    int rows = 0;
    //记录结果的列数
    int columns = 0;
    //获取查询结果
    res = mysql(store_result(p_sock));
    if(res == NULL)
    {
        printf("获取结果集错误:%s\n",mysql_error(p_sock));
        return -1;
    }
    //获取查询结果的行数
    rows = mysql_num_rows(res);
    if(rows < 0)
    {
        printf("获取查询结果的行数错误:%s\n",mysql_error(p_sock));
        return -1;
    }
    if(rows == 0)
    {
        printf("该查询结果中无数据!\n");
        return 0;
    }

    //获取查询结果的列数
    columns = mysql_num_fields(res); 
    if(rows < 0)
    {
        printf("获取查询结果的列数错误:%s\n",mysql_error(p_sock));
        return -1;
    }

    //获取每一行数据
    while((row = mysql_fetch_row(res)) != NULL)
    {
        int i;
        for(i = 0;i < columns;i++)
        {
            printf("%s\t",rows[i]);
        }
        printf("\n");
    }

    //释放结果集所占用的空间
    mysql_free_result(res);
    return 0;}
}

//插入
int Insert_sql(MYSQL *p_sock)
{
    char buffer[1024] = {0};
    //sql语句
    memset(buffer,0x00,1024);
    snprintf(buffer,1023,"%s","insert into Department(Department_id,Department_name,Remark) value('D07','综合部','综合部')");
    //执行sql语句
    if(mysql_query(p_sock,buffer) != 0)
    {
        perror("mysql_query");
        return -1;
    }
    return 0;
}

//更新
int Update_sql(MYSQL *p_sock)
{
    char buffer[1024] = {0};
    //sql语句
    memset(buffer,0x00,1024);
    snprintf(buffer,1023,"%s","update Department set Remark = "综合管理" where Department_id = 'D07'");
    //执行sql语句
    if(mysql_query(p_sock,buffer) != 0)
    {
        perror("mysql_query");
        return -1;
    }
    return 0;
}

//删除
int Delete_sql(MYSQL *p_sock)
{
    char buffer[1024] = {0};
    //sql语句
    memset(buffer,0x00,1024);
    snprintf(buffer,1023,"%s","delete from Department where Department_id = 'D07'");
    //执行sql语句
    if(mysql_query(p_sock,buffer) != 0)
    {
        perror("mysql_query");
        return -1;
    }
    return 0;
}


int main()
{
    //按照文档中的步骤,首先进行对sql环境的初始化

    //1.初始化sql环境
    //定义MYSQL变量
    MYSQL mysql,*p_mysql,*p_sock;
    //初始化mysql句柄
    p_mysql = mysql_init(&mysql);
    if(p_mysql == NULL)
    {
        printf("初始化错误!\n");
        return -1;
    }
    //初始化MySQL库
    int ret = mysql_library_init(0,NULL,NULL);
    if(ret ==0)
    {
        printf("初始化数据库成功!\n");
    }
    else
    {
        printf("初始化数据库失败!\n");
        return -1;
    }
    if(p_mysql != NULL && ret == 0)
    {
        printf("初始化sql环境成功!\n");
    }

    //2.连接数据库
    p_sock = mysql_real_connect(p_mysql,"127.0.0.1","root","(NavyBlue123)",NULL,0,NULL,0);
    if(p_sock == NULL)
    {
        //输出错误原因
        printf("连接错误:%s\n",mysql_error(p_mysql));
        return -1;
    }
    //选择数据库
    int r = mysql_swlect_db(p_sock,"StaffDB");
    if(r != 0)
    {
        printf("选择数据库出错:%s\n",mysql_error(p_mysql));
        return -1;
    }
    //设置编码格式,注意,此处一定要设置编码格式,不然最后的查询结果中的中文会显示乱码
    mysql_query(&mysql,"SET NAMES utf8");
    if(p_sock != NULL && r == 0)
    {
        printf("数据库连接成功!\n");
    }

    //3.执行sql语句,此部分我们另写函数实现
    //查询部分我们选择查询3张表的整体信息
    Select_sql(p_sock);
    //插入部分我们选择给Staff表中插入一条新的员工信息
    Insert_sql(p_sock);
    //修改,即更新
    Update_sql(p_sock);
    //删除部分我们选择删除新插入到Staff表中的那条员工信息
    Delete_sql(p_sock);

    //4.获取查询结果,此部分会在执行sql语句的函数里一并处理

    //5.关闭数据库
    mysql_close(&mysql);

    //6.释放sql环境,终止使用MySQL库
    mysql_library_end();

    return 0;
}

         由于本鸟的Mysql在安装的时候丢失了重要的文件,所以此文件无法运行,还希望大家在闲余时间能够亲自跑一下代码,熟悉一下连接过程为好。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux下访问数据库 的相关文章

随机推荐

  • 使用vuex实时更新右上角通知信息的红点数量

    需求如图 因为这两个不存在组件关系 所以我们使用Vuex来解决这个实时刷新 1 首先在vuex的state定义数据如下 state noticeCount 0 2 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
  • ensp usg6000v ping不通_华为USG6000V防火墙和VMWARE的联动

    快到周末了 来一篇技术类公众号文章 最近看一本很有意思的书 叫 华为防火墙技术漫谈 俗话说得好 理论结合实践才是王道 下面来简要描述一下本周做过的一个比较有意思的实验 在这个实验中使用到了ENSP模拟器 USG6000V防火墙 VMWARE
  • 【数模研赛】“华为杯”第十九届中国研究生数学建模竞赛C题分享——(四)问题二模型建立

    写在前面 第十九届数模研赛在22年10月6 10日开展 我和我的两名队友肝了5天 整出来一篇论文 因为不确定自己做的好不好 所以一直没写博客 前两天结果出来了 我们队拿了国二 在C题里排名88 1134 感觉结果还不错 以后应该也不会再有机
  • UE4 实现控制场景中所有物体透明度功能

    本文会讲解如何利用材质参数集简单的实现修改场景中所有物体透明度的功能 讲解地图为第三人称地图 1 创建材质变量集 这里面新建的变量可以在蓝图中控制 这样就能很方便的修改透明度 因为透明度是只有一个值的参数所以创建scalar参数 默认值为1
  • c语言的product,张永强:C语言中product是什么意思

    吴俊光的回答 product在C语言中不是关键字 C库中也没有这样的函数名 所以pruduct有两种可能 1是编程者自己定义的变量 2是编程者自定义的函数的名字 这里product是自定义函数的名字 功能就是返回a乘b的结果 实现一个乘法功
  • 【转载】Linux下用ls和du命令查看文件以及文件夹大小

    1 ls的用法 ls ll 列出当前目录下所有文件的大小以及所有文件大小的统计总和 显示成字节大小 ls lh 列出当前目录下所有文件的大小以及所有文件大小的统计总和 以KB MB等为单位进行显示 ls l grep wc l 或 find
  • 基于BCM53262交换芯片平台的Linux操作系统移植(四)之代码调试与驱动书写

    2018 05 09 10 49 zhoulinhua 2018 05 10 一 系统分区 name address size bootstrap 0x0 64k u boot 0x10000 640k env 0xb0000 192k d
  • 【C语言】练习题 - 菲姐游泳 - 附视频讲解

    游泳奥运冠军菲姐刻苦训练 从早上a时b分开始下水训练 直到当天的c时d分结束 请编程计算 菲姐当天一共训练多少小时多少分钟 本文引用自作者编写的下述图书 本文允许以个人学习 教学等目的引用 讲授或转载 但需要注明原作者 海洋饼干叔 叔 本文
  • 独立按键消抖与松手检测

    记录下最近独立按键消抖和松手检测 我对独立按键的处理思路是 1 获得键值 2 消抖处理 3 松手检测 4 键值解析 1 获得键值 这里把独立按键做个编号 例如有两个按键记为KEY0 KEY1 用一个变量来记录当前按键标记值 比如Cur Ke
  • npm install 编译时报“Cannot read properties of null (reading ‘pickAlgorithm‘)“

    先看报错 先说下网上大多数的解决方案 方案一 重新安装node解决 方案二 删了node models重新下 或者直接下载CNPM 淘宝镜像 进行安装 CNPM安装办法 npm install g cnpm registry https r
  • 解决STM32驱动0.96OLED不亮的问题

    问题描述 使用STM32无法驱动OLED 解决方案 1 检查硬件连接是否有误 OLED STM32 VCC 5V或3 3V SDA SDA SCL SCL GND GND 备注 最好接STM32最小系统版的3 3V 当连接STM32最小系统
  • Javaio流

    io流 关于Java的io流一般按照数据操作类型可以分为字节流与字符流 首先来说一下字节流 字节流 字节流的方法都是以stream结尾的 字节流的用途 转换图片为二进制 转换音频 视屏为二进制 字符串等也可以转为二进制 字节流常用于图片 音
  • 签到题【牛客算法周周练6E】【暴力枚举+线段树】

    题目链接 题目保证数据随机 数据随机真的是太强了 直接可以跑最坏时候是的复杂度 直接暴力建线段树 然后更新的时候更新到底 查询的时候也是查询到底 因为数据随机 所以其实被处理的次数是很少的 因为要刚好是set里有的 或者是set里没有的 这
  • Unity3D-----三维数学(向量)

    Unity3d gt 三维数学之向量 一 向量 1 什么是向量 2 向量的形式 3 向量的大小 4 向量的方向 二 向量运算 1 向量相减 2 向量相加 3 向量与标量的乘除法 4 点乘 5 叉乘 三 三角函数 1 角的度量单位 2 三角函
  • Labelme 目标检测和语义分割的数据标注

    1 安装labelme 打开conda prompt 输入以下代码创建虚拟环境 打开虚拟环境 安装lelme conda create n labelme python 3 6 创建虚拟环境 conda activate labelme 打
  • 解决idea出现报错:Error running,Command line is too long. Shorten command line

    报错的原因 因为项目需要打印的环境变量太长 超过了限制 需要缩短命令行来解决问题 解决办法 方法一 Edit Configurations 将默认的Shorten command line的值user local default 改为 JA
  • 格式工厂多个图片合并成一个PDF的报错

    使用图片合并PDF功能时 当图片数量超过50会报错 找到imgconv py文件 将50改为500 保存 现在可以支持100张图合并成一个PDF文件了 但是超过150张程序会直接闪退 正在解决中 补充说明 1 如何设置PDF压缩比 打开 g
  • 有奖调研

    简介 感谢您一直以来对阿里云通信短信服务的支持 为了提升用户体验 为您在数字化转型的通信之路提供助力 云通信短信服务将发起一次满意度调研 有关短信服务 无论使用情况 抑或功能需求 还是文档 产品介绍页 计算与账单 控制台 API SDK 售
  • TypeError Cannot read properties of undefined (reading ‘matched‘)vue项目创建之后写路由报错

    vue项目创建之后写路由报错 原代码 修改之后代码 在 import 路由文件后 命名为Router 就会出现报错 原因 router 才是Vue实例化的配置字段名称 不识别其他的
  • Linux下访问数据库

    Linux下访问数据库 声明 本文只简单描述Linux系统下访问mysql数据库的步骤 关于连接上数据库之后的简单的对于数据库的增删改查等操作只是稍微提及 关于增删改查的语句书写 本文不再讲述 一般来说 访问数据库有如下几个步骤 1 初始化