ubuntu18.04下mysql数据库C语言API封装

news2024/11/15 23:20:50

  mysql C语言API操作数据库比较繁琐,可以将其封装起来,这样使用比较方便,下面是一种封装方式。

目录

1.连接封装

2.连接池封装

3.测试代码


1.连接封装

        将数据库连接进行封装,主要提供如下接口:

(1)连接操作

(2)更新操作(增加 /  删除 / 修改 )

(3)查询操作(查询要获取结果集,所以单独封装一个接口)

(4)获取下一条记录

(5)获取查询结果的列数(为了遍历一行中各个列时使用)

(6)获取一条记录的某个字段值

(7)设置手动提交事务(mysql默认自动提交事务)

(8)提交事务

(9)回滚事务

头文件:ConnMysql.h

#pragma once
#include <iostream>
#include <string>
#include <mysql/mysql.h>
#include <chrono>

using namespace std;

class ConnMysql {
public:
   ConnMysql();
   ~ConnMysql();
   bool Connect(const std::string &ip,
            const std::string &user,
            const std::string &pwd,
            const std::string &db,
            const unsigned short &port);
   bool Update(const std::string &sql);
   bool Query(const std::string &sql);
   bool Next();
   unsigned int GetColNum();
   std::string GetValue(const int& index);
   bool SetTransaction();
   bool Commit();
   bool Rollback(); 

private:
    void init();
    void uninit();
    void freeResult();

private:
    MYSQL *m_mysql;
    MYSQL_RES *m_result;
    MYSQL_ROW m_row = nullptr;
};

实现文件:ConnMysql.cpp

#include "ConnMysql.h"

using namespace chrono;

ConnMysql::ConnMysql() {
    init();
}

ConnMysql::~ConnMysql() {
    uninit();
}

bool ConnMysql::Connect(const std::string &ip,
            const std::string &user,
            const std::string &pwd,
            const std::string &db,
            const unsigned short &port) {
    if (!m_mysql) {
        return false;
    }
    m_mysql = mysql_real_connect(m_mysql, ip.c_str(), user.c_str(), pwd.c_str(), db.c_str(), port, NULL, 0);
    if (!m_mysql) {
        return false;
    }
    return true;    
}

bool ConnMysql::Update(const std::string &sql) {
    if (mysql_query(m_mysql, sql.c_str())) {
        return false;
    }
    return true;
}

bool ConnMysql::Query(const std::string &sql) {
    freeResult();
    if (mysql_query(m_mysql, sql.c_str())) {
        return false;
    }
    m_result = mysql_store_result(m_mysql);
    return true; 
}

bool ConnMysql::Next() {
    if (!m_result) {
        return false;
    }
    m_row = mysql_fetch_row(m_result);
    if (m_row) {
        return true;
    }
    return false;
}

unsigned int ConnMysql::GetColNum() {
    return mysql_num_fields(m_result);
}

std::string ConnMysql::GetValue(const int& index) {
    //获取结果集列数
    int rowNum = mysql_num_fields(m_result);
    if (index >= rowNum || index < 0) {
        return std::string("");
    }
    char* value = m_row[index];
    auto length = mysql_fetch_lengths(m_result)[index];
    return std::string(value, length);
}

bool ConnMysql::SetTransaction() {
    return mysql_autocommit(m_mysql, false);
}

bool ConnMysql::Commit() {
    return mysql_commit(m_mysql);
}

bool ConnMysql::Rollback() {
    return mysql_rollback(m_mysql);
}

void ConnMysql::init() {
    m_mysql = nullptr;
    m_result = nullptr;
    m_mysql = mysql_init(nullptr);
    if (m_mysql) {
        mysql_set_character_set(m_mysql, "utf8");
    }
}

void ConnMysql::uninit() {
    freeResult();
    if (m_mysql) {
        mysql_close(m_mysql);
        m_mysql = nullptr;
    }
}

void ConnMysql::freeResult() {
    if (m_result) {
        mysql_free_result(m_result);
        m_result = nullptr;
    }
}

2.连接池封装

       mysql的api通过tcp/ip协议连接数据库服务器,建立连接和断开连接需要经历三次握手和四次挥手,频繁的连接和断开会使得程序运行效率很低,可以采用连接池的方式来提高操作数据库效率,连接池的本质就是复用连接,一个连接可以重复使用,避免和服务器频繁建立连接和断开连接,从而提高程序执行效率。

头文件:ConnMysqlPool.h

#pragma once
#include <string>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include "ConnMysql.h"

using namespace std;

class ConnMysqlPool {
public:
    ConnMysqlPool(const ConnMysqlPool&) = delete;
    ConnMysqlPool& operator=(const ConnMysqlPool&) = delete;
    static ConnMysqlPool& instance();
    ~ConnMysqlPool();
    std::shared_ptr<ConnMysql> GetConn();

private:
    ConnMysqlPool(const std::string &ip = "127.0.0.1",
                const unsigned short &port = 3306,
                const std::string &user = "root",
                const std::string &pwd = "mysql",
                const std::string &db = "TestDB",
                const int &min = 5,
                const int &max = 10,
                const int &idleTime = 60,
                const int &timeout = 60);
    void init();
    void addNewConn();

private:
    std::string m_ip;
    unsigned short m_port;
    std::string m_user;
    std::string m_pwd;
    std::string m_db;
    int m_min;
    int m_max;
    int m_idleTime;
    int m_timeout;
    std::mutex m_mutex;
    std::condition_variable m_cond;
    std::queue<std::shared_ptr<ConnMysql>> m_connQueue;
    std::atomic_bool m_exit;
};


实现文件:ConnMysqlPool.cpp

#include <thread>
#include <chrono>
#include "ConnMysqlPool.h"

ConnMysqlPool::ConnMysqlPool(const std::string &ip,
                const unsigned short &port,
                const std::string &user,
                const std::string &pwd,
                const std::string &db,
                const int &min,
                const int &max,
                const int &idleTime,
                const int &timeout) : 
m_ip(ip),
m_port(port),
m_user(user),
m_pwd(pwd),
m_db(db),
m_min(min),
m_max(max),
m_idleTime(idleTime),
m_timeout(timeout),
m_exit(false)   
{
    init();
}

ConnMysqlPool::~ConnMysqlPool() {
    m_exit.store(false);
    m_cond.notify_all();
    while (!m_connQueue.empty()) {
        m_connQueue.pop();
    }
}


ConnMysqlPool& ConnMysqlPool::instance() {
    static ConnMysqlPool s_instance;
    return s_instance;
}

std::shared_ptr<ConnMysql> ConnMysqlPool::GetConn() {
    std::unique_lock<std::mutex> lock(m_mutex);
    while (m_connQueue.empty()) {
        if (m_connQueue.empty()) {
            if (cv_status::timeout == m_cond.wait_for(lock, chrono::milliseconds(m_timeout))) {
                if (m_connQueue.empty()) {
                    continue;
                }
            }
        }
    }
    auto mysql = m_connQueue.front();
    m_connQueue.pop();
    m_cond.notify_all();
    return mysql;
}

void ConnMysqlPool::init() {
    for (int i = 0; i < m_min; i++) {
        addNewConn();
    }
    std::thread producer([this](){
        while (m_exit) {
            std::unique_lock<std::mutex> lock(m_mutex);
            //此处使用while,养成条件变量判断使用while而不是使用if
            while (m_connQueue.size() >= m_min) {
                m_cond.wait(lock);
            }
            addNewConn();
            m_cond.notify_all();
        }
        
    });
    producer.detach();
}

void ConnMysqlPool::addNewConn() {
    std::shared_ptr<ConnMysql> mysql(new ConnMysql, [this](ConnMysql* conn) {
        std::lock_guard<std::mutex> lock(m_mutex);
        m_connQueue.push(std::shared_ptr<ConnMysql>(conn));
    });
    mysql->Connect(m_ip, m_user, m_pwd, m_db, m_port);
    m_connQueue.push(mysql);
}

3.测试代码

#include <iostream>
#include "ConnMysql.h"
#include "ConnMysqlPool.h"

using namespace std;

//mysql8.0连接数据库需要对数据进行加密,调用api库时需要额外的加密库
//多个线程使用同样的用户名和密码同时去连接数据库,数据库会拒绝一些连接,解决办法是在同时连接前先单独连接一次
void testConnMysql() {
    ConnMysql mysql;
    mysql.SetTransaction();
    mysql.Connect("127.0.0.1", "root", "mysql", "TestDB", 3306);
    std::string sql = "insert into employee(name, address, age, position, remark) values('张三', '陕西', 21, 'higher', '路人甲')";
    if (mysql.Query(sql)) {
        mysql.Commit();
        std::cout << "insert ok !" << std::endl;
    }
    else {
        mysql.Rollback();
        std::cout << "insert error !" << std::endl;
    }
    sql = "select * from employee";
    if (mysql.Query(sql)) {
        std::cout << "select ok !" << std::endl;
        auto colNum = mysql.GetColNum();
        while (mysql.Next()) {
            for(int i = 0; i < colNum; i++) {
                std::cout << mysql.GetValue(i) << " ";
            }
            std::cout << std::endl;
        }
    }
    else {
        std::cout << "select error !" << std::endl;
    }

}

void testConnMysqlPool() {
    auto mysqlConn = ConnMysqlPool::instance().GetConn();
    mysqlConn->SetTransaction();
    std::string sql = "insert into employee(name, address, age, position, remark) values('李四', '北京', 22, 'higher', '路人乙')";
    if (mysqlConn->Query(sql)) {
        mysqlConn->Commit();
        std::cout << "insert ok !" << std::endl;
    }
    else {
        mysqlConn->Rollback();
        std::cout << "insert error !" << std::endl;
    }
    sql = "select * from employee";
    if (mysqlConn->Query(sql)) {
        std::cout << "select ok !" << std::endl;
        auto colNum = mysqlConn->GetColNum();
        while (mysqlConn->Next()) {
            for(int i = 0; i < colNum; i++) {
                std::cout << mysqlConn->GetValue(i) << " ";
            }
            std::cout << std::endl;
        }
    }
    else {
        std::cout << "select error !" << std::endl;
    }
}

int main(int argc, char* argv[]) {
    std::cout << "test1 ..." << std::endl;
    testConnMysql();
    std::cout << "test2 ..." << std::endl;
    testConnMysqlPool();
    std::cout << "end" << std::endl;
    return 0;
}

Makefile

app: useMysqlConnPool

useMysqlConnPool: usemysqlconnpool.cpp ConnMysql.cpp ConnMysqlPool.cpp  
	g++ -std=c++11 -g $^ -o useMysqlConnPool -lpthread -lmysqlclient 

clean:
	-rm useMysqlConnPool -f

运行结果如下:

 数据库数据:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/134457.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

L2-030 冰岛人

2018年世界杯&#xff0c;冰岛队因1:1平了强大的阿根廷队而一战成名。好事者发现冰岛人的名字后面似乎都有个“松”&#xff08;son&#xff09;&#xff0c;于是有网友科普如下&#xff1a; 冰岛人沿用的是维京人古老的父系姓制&#xff0c;孩子的姓等于父亲的名加后缀&#x…

torchnet.meter使用教程

前言 最近项目开发过程中遇到了torchnet.metertorchnet.metertorchnet.meter来记录模型信息&#xff0c;搜了好多篇博客潦潦草草&#xff0c;没有一点干货&#xff0c;于是根据官方代码和官方文档&#xff0c;基于自己的理解&#xff0c;制定了使用教程: torchnet简介 torch…

一句话实现报表生成PDF同时通过outlook发送

元旦节快乐 哈喽&#xff0c;大家2023年好呀&#xff01; 今天&#xff0c;元旦最后一天&#xff0c;给大家分享什么好玩的示例呢&#xff1f; 让我来想想&#xff0c;嗯&#xff1f;这样可以吗&#xff1f;一句话就实现将报表生成PDF&#xff0c;同时可以编辑一些信息并通过…

【源码分享】java多用户B2B2C商城源码带WAP手机端源码

分享一款非常不错的java多用户B2B2C商城源码&#xff0c;带WAP手机端源码&#xff0c;源码地址在文末。 需要源码学习&#xff0c;可私信我获取。 一、技术构架&#xff1a; 开发语言&#xff1a; Java1.7 数 据 库 &#xff1a; MySQL5.5 数据库持久层&#xff1a;阿里巴巴…

车载诊断协议UDS——会话模式状态机Session

UDS之Session服务 会话模式管控是汽车电子诊断范畴很重要的两个状态机之一(另一个是安全访问),不同的会话模式是用来区分诊断服务执行权限。 一位非常尊敬的业内前辈曾举如下例子来形容这个状态机:不同的场景,喝对应的酒! 公司商务场合下,对应的酒是红酒;长辈酒桌上,对…

Redis 哨兵模式

哨兵是一个分布式系统&#xff0c;你可以在一个架构中运行多个哨兵进程&#xff0c;这些进程使用流言协议来接收关于Master主服务器是否下线的信息&#xff0c;并使用投票协议来决定是否执行自动故障迁移&#xff0c;以及选择哪个Slave作为新的Master。 一、哨兵模式概述 1.1…

ubuntu做系统常见出错处理方法1

1.不能分区解决办法&#xff08;安装ubuntu没有出现安装选项&#xff0c;也就是找不到硬盘分区怎么办?-爱码网&#xff09; 解决办法是进入bios模式(一般都是重启时反复按f12&#xff0c;不同电脑型号可自行查阅)把硬盘模式从raid调整为ahci(System configuration–&#xff…

方差和标准差的意义

文章目录案例&#xff1a;箭靶案例&#xff1a;身高案例&#xff1a;身高体重在此前一篇文章 《算法效果评估&#xff1a;均方根误差&#xff08;RMSE&#xff09;/ 标准误差》中&#xff0c;我们介绍了方差/标准差的计算方法&#xff0c;也点出了它们是用来“度量数据离散程度…

linux系统中wifi驱动的配置与编译实现方法

大家好&#xff0c;今天主要和大家聊一聊&#xff0c;如何使用linux系统中的WIFI驱动完成相应的实验。 目录 第一&#xff1a;WIFI驱动添加与编译方法 第二&#xff1a;将驱动代码添加到linux内核中 第三&#xff1a;配置Linux内核 第四&#xff1a;编译WIFI驱动 第一&…

YOLOv5更换骨干网络之 MobileNetV3

论文地址&#xff1a;https://arxiv.org/abs/1905.02244 代码地址&#xff1a;https://github.com/xiaolai-sqlai/mobilenetv3 我们展示了基于互补搜索技术和新颖架构设计相结合的下一代 MobileNets。MobileNetV3通过结合硬件感知网络架构搜索&#xff08;NAS&#xff09;和 N…

MySQL基础篇

MySQL数据库笔记 第一部分 MySQL基础篇 第01章 数据库概述 1. 为什么要使用数据库 持久化(persistence)&#xff1a;把数据保存到可掉电式存储设备中以供之后使用。大多数情况下&#xff0c;特别是企业级应用&#xff0c;数据持久化意味着将内存中的数据保存到硬盘上加以“…

网络类型实验

1.先配ip [Huawei]sysname R1 [R1]interface GigabitEthernet 0/0/1 [R1-GigabitEthernet0/0/1]ip add 192.168.1.1 24 [R1-GigabitEthernet0/0/1]int s 4/0/0 [R1-Serial4/0/0]ip add 12.1.1.1 24 其他同理 2.写三条缺省指向R2来使网络通 [R1]ip route-static 0.0.0.0 0 12…

【王道操作系统】3.1.1 什么是内存?进程的基本原理,深入指令理解其过程

什么是内存&#xff1f;进程的基本原理&#xff0c;深入指令理解其过程 文章目录什么是内存&#xff1f;进程的基本原理&#xff0c;深入指令理解其过程1.什么是内存&#xff1f;有何作用&#xff1f;2.进程运行的基本原理2.1 指令的工作原理---操作码若干参数2.2 逻辑地址(相对…

C++类和对象3:关于类内部的更多细节

目录 初始化列表&#xff1a; explicit关键字 ​编辑 static成员 友元 内部类 匿名对象 拷贝对象时的一些编译器优化 我们已经接触过了构造函数&#xff0c;其功能可以很方便的帮助我们为变量赋值&#xff0c;但是在这里并不是初始化&#xff0c;因为一个构造函数可以为几…

02 Hadoop概述

Hadoop概述1、Hadoop是什么2、Hadoop版本3、HDFS、YARN、MapReduce&#xff08;1&#xff09; HDFS&#xff08;2&#xff09;YARN&#xff08;3&#xff09;MapReduce&#xff08;3&#xff09;Hadoop模块之间的关系1、Hadoop是什么 是一个由Apache基金会开发的分布式系统基础…

动态规划是个好东西:编辑距离

力扣&#xff1a;72. 编辑距离 这道题目让我狠狠的了解了动态规划&#xff0c;这玩意是真强。 题目描述很简单&#xff1a; 这道题正常来说&#xff0c;我们要考虑这个字符怎么换&#xff0c;长度不一怎么找…等等问题&#xff0c;但是这样做会发现很困难&#xff0c;显然这是…

Vert.x 核心概念及事件模型

Vert.x是基于事件的&#xff0c;提供一个事件驱动编程模型 使用Vert.x作为服务器时&#xff0c;程序员只要编写事件处理器event handler即可。&#xff08;当TCP socket有数据时&#xff0c;event handler被创建调用&#xff09; 另外它还可以在以下几种情况激活&#xff1a; …

反向迭代器

文章目录1. list的反向迭代器2. list的rbegin和rend3. 反向迭代器的实现3.1 复用vector反向迭代器3.2 反向迭代器的变化1. list的反向迭代器 我们先来看一看库里面的list的迭代器是如何写的&#xff1a; 这是list的正向迭代器。 这是list的反向迭代器。 其实大佬们是把正向迭…

【3.1】Eureka注册中心-提供者与消费者/原理分析

【3.1】Eureka-提供者与消费者/原理分析1 提供者与消费者2 服务调用出现的问题3 Eureka的作用3.1 消费者该如何获取服务提供者具体信息&#xff1f;3.2 如果有多个服务提供者&#xff0c;消费者该如何选择&#xff1f;3.3 消费者如何感知服务提供者健康状态&#xff1f;4 总结1…

A. The Enchanted Forest #769 div1

Problem - A - Codeforces 题意&#xff1a; 给你一串序列&#xff0c;任意从什么地方开始&#xff0c;给你k秒时间&#xff0c;让你算最大价值 每一秒时间按顺序你可以做&#xff1a; ①移动到|x-y|<1的地方 ②取走这个位置上所有的数 ③每个位置1 原来是0秒&#x…