c++ 实现数据库连接池

2023-11-08

c++ 实现数据库连接池

自己尝试用c++ 新标准实现了数据库连接池,代码简化了很多。


思路:
将数据库的连接当作一个对象添加进list队列中,在连接池创建的时候就建立好队列,并添加自定义大小的连接对象,连接对象用智能指针来管理(现代c++中不应该出现delete语句),避免类似内存泄漏等内存问题,智能指针上用lambda表达式注册了delete删除函数来释放连接资源,及时归还,(其中用了std::move来转移list中的对象所有权到函数里的临时智能指针对象,当离开作用域时,自动释放。)


关于数据库连接池介绍可以看下面两篇文章:

浅析数据库连接池(一)

浅析数据库连接池(二)


代码:

mysql_connect.h

#ifndef _MYSQL_CONNECTION_
#define _MYSQL_CONNECTION_

//c++
#include <iostream>
#include <string>
#include <list>
#include <memory>
#include <functional>

//mysql driver
#include <mysql_driver.h>
#include <mysql_connection.h>

//mysql execute
#include <cppconn/driver.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>
#include <cppconn/resultset.h>
#include <exception>

//thread mutex 
#include <mutex>

using namespace sql;
using delFunc = std::function<void(Connection*)>;

class ConnectionPool
{
    public:
        //获取数据库连接池对象 static单例模式
        static ConnectionPool* getInstance();
        //得到一条连接
        auto getConnect()->std::shared_ptr<Connection>;
        //归还一条连接
        auto retConnect(std::shared_ptr<Connection> &ret)->void;
        ~ConnectionPool();


    private:
        ConnectionPool(std::string name, std::string pwd, std::string nurl, int maxSize);
        //初始化连接池
        auto initConnectPool(int initialSize)->void;
        //毁坏连接池
        auto destoryPool()->void;
        //destory one connection
        auto destoryOneConn()->void;
        //扩大数据库连接池
        auto expandPool(int size)->void;
        //缩小数据库连接池
        auto reducePool(int size)->void;
        //add conn
        auto addConn(int size)->void;
    public:
        //get size
        auto getPoolSize()->int;

    private:
        std::string username; //帐号
        std::string password; //密码
        std::string url;      //连接url
        int poolSize;       //pool size

        //存放所有连接
        std::list<std::shared_ptr<Connection>> conList;

        static ConnectionPool *pool;//连接池对象
        std::mutex lock;//锁
        Driver *driver;//mysql driver
};



#endif

mysql_connect.cpp

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "mysql_connect.h"

ConnectionPool*
ConnectionPool::pool = nullptr;

//private
//构造函数
ConnectionPool::ConnectionPool(std::string name, std::string pwd, std::string nurl, int maxSize):
    username(name), password(pwd), url(nurl), poolSize(maxSize)
{
    //得到mysql驱动
    driver = get_driver_instance();
    //开始初始化大小一半
    initConnectPool(poolSize/2);
}

//析构函数
ConnectionPool::~ConnectionPool()
{
    destoryPool();
}

//得到连接池大小
int
ConnectionPool::getPoolSize()
{
    return conList.size();
}

//增加连接
void
ConnectionPool::addConn(int size)
{
    for(int i = 0; i < size; ++i)
    {
        //创建连接
        Connection *conn = driver->connect(url, username, password);
        std::shared_ptr<Connection> sp(conn, 
                [](Connection *conn){
                    delete conn;
                });
        conList.push_back(std::move(sp));
    }
}

//初始化连接池
void
ConnectionPool::initConnectPool(int initialSize)
{
    //加锁,增添一个连接
    std::lock_guard<std::mutex> locker(lock);
    addConn(initialSize);
}

//销毁一个连接
void
ConnectionPool::destoryOneConn()
{
    //智能指针加std::move转移一个连接的“所有权”,当出作用域时,自动调用关闭connect
    std::shared_ptr<Connection> &&sp = std::move(conList.front());
    sp->close();
    --poolSize;
}

//销毁整个连接池
void 
ConnectionPool::destoryPool()
{
    for(auto &conn : conList)
    {
        //依次转移所有权,出作用域时,关闭连接,出作用域时智能指针自动释放
        std::shared_ptr<Connection> &&sp = std::move(conList.front());
        sp->close();
    }
}

//扩大连接池
void
ConnectionPool::expandPool(int size)
{
    std::lock_guard<std::mutex> locker(lock);
    addConn(size);
    poolSize += size;
}

//缩小连接池
void
ConnectionPool::reducePool(int size)
{
    std::lock_guard<std::mutex> locker(lock);
    //减小的大小不能超过存储的大小
    if(size > poolSize)
    {
        return;
    }
    for(int i = 0; i < size; i++)
    {
        //sp point new object, old object release
        destoryOneConn();
    }
    poolSize -= size;
}

//public
//得到连接池实例
ConnectionPool*
ConnectionPool::getInstance()
{
    if(pool == nullptr)
    {
        //3306是mysql占用的端口,其实创建40个连接
        pool = new ConnectionPool("root", "********", "tcp://127.0.0.1:3306", 40); 
    }
    return pool;
}

//得到一个连接
std::shared_ptr<Connection>
ConnectionPool::getConnect()
{
    std::lock_guard<std::mutex> locker(lock);
    std::shared_ptr<Connection> sp = conList.front();
    conList.pop_front();
    return sp;
}

//归还一个连接
void
ConnectionPool::retConnect(std::shared_ptr<Connection> &ret)
{
    std::lock_guard<std::mutex>locker(lock);
    conList.push_back(ret);
}

try.cpp

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <mysql_connect.h>
#include <unistd.h>

ConnectionPool *pool = ConnectionPool::getInstance();

int main(int argc, char *argv[])
{
    std::shared_ptr<Connection>con;
    Statement *state;
    ResultSet *result;

    //获得一个连接
    con = pool->getConnect();
    //获得一个数据库连接对象
    state = con->createStatement();
    //使用XL_db这个数据库
    state->execute("use XL_db");
    //查询语句
    result = state->executeQuery("select * from UserInfo;");
    while(result->next())
    {
        int id = result->getInt("uid");
        std::string name = result->getString("password");
        std::cout << "id:" << id << " name:" << name << std::endl; 
    }
    sleep(10);
    pool->retConnect(con);
    std::cout << pool->getPoolSize() << std::endl;
    sleep(10);

    return EXIT_SUCCESS;
}

我自己进行了测试,创建数据库连接池,调用一个对象,然后执行数据库连接,查询出了结果,然后归还一个连接。


创建连接池前
这里写图片描述

创建连接池后
这里写图片描述

Id 792是我调用的那个连接,然后执行查询操作,所以db显示的是连接上XL_db。

这个是自己写的一个简单的数据库连接池,可以参考下,如果要使用的话还需要自己改改。
这些××池之类,比如线程池,进程池,连接池等原理都差不多,就是先创建一批对象,然后一个队列里保存,需要的时候来取,用完归还就行,然后通过c++11新特性等我们能提升性能和安全性以及程序的简介性,比如刚才说的std::move和智能指针,lambda等。

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

c++ 实现数据库连接池 的相关文章

  • 仅使用扩展方法在 Linq 中进行漂亮、干净的交叉连接 [重复]

    这个问题在这里已经有答案了 可能的重复 使用扩展方法表示的嵌套 from LINQ 查询 https stackoverflow com questions 9115675 nested from linq query expressed
  • 如何使用 ILoggerFactory 记录 Polly 的重试

    或者 如何从静态方法记录 From https github com App vNext Polly https github com App vNext Polly你有这样的例子 其中记录器神奇地可用 Policy Timeout 30
  • WP8.1 C# 绑定联系人图像

    信息很简单 我正在尝试创建一个可以显示用户联系人的应用程序 我也是一名自学成才的程序员 所以我在某些方面有编程经验 但总体来说我对数据绑定相对较新 首先 我有一个 ListView 控件 其中包含图像绑定
  • 操作/Lambda 表达式内存管理问题

    我将一个操作存储在局部变量中 然后在该局部变量超出范围后使用 使用前是否有被清理的危险 这是一个例子 public List GetMaps Action
  • “包含字符串”的快速索引

    在我的应用程序中 我有多达数百万个短字符串 大部分短于 32 个字符 我想实现一个带有附加列表的搜索框 该列表仅包含包含在搜索框中输入的整个字符串的元素 如何预先建立索引来快速找到此类字符串 所有排序的 STL 容器都会检查整个字符串 对于
  • 在 C# 中调用事件处理程序

    我一直在尝试学习如何在 C 中使用事件处理程序 但我无法弄清楚 handler this e 在以下代码中的作用 public event EventHandler ThresholdReached protected virtual vo
  • 读取STM32 MCU SPI数据寄存器的值

    有很多类似的问题 但似乎没有一个问题完全相同 我正在将 STML4 MCU 连接到 6 轴传感器 LSM6DS3 我已经成功地在 I2C 中实现了所有内容 但想要 SPI 的额外速度 和 DMA 如果我能让这些第一步工作起来的话 因此 第一
  • 命名空间“Microsoft”中不存在类型或命名空间名称“Practices”

    我正在使用 Microsoft Visual Studio 2005 for c 我的代码中有以下命名空间 using Microsoft Practices EnterpriseLibrary using Microsoft Practi
  • 如何填充两个样条线或直线系列之间的区域

    我有这个Chart 如何填充两个之间的区域Series S0 and S1 说蓝色和黄色Series 为此 我们编写了其中之一Paint事件 这里的ValueToPixelPosition https msdn microsoft com
  • 带双重检查锁的单例设计模式

    假设您有以下代码 1 为什么我们使用双重检查锁 为什么单锁不够好 请提供详细的例子 2 这种实施方式的主要缺点是什么 我该如何证明呢 Thanks public sealed class SomeSingleton5 private sta
  • printf() 使用字符串表“解码器环”调试库

    我写这封信是想看看你们中是否有人见过或听说过我即将描述的想法的实现 我有兴趣为嵌入式目标开发 printf 风格的调试库 目标非常遥远 并且我和目标之间的通信带宽预算非常紧张 因此我希望能够以非常有效的格式获取调试消息 通常 调试语句如下所
  • EWS - 给予预约,获取预约的所有者副本

    在 EWS 中进行预约后 是否可以获得所有者的副本 例如 如果我登录为user1 我有user1创建的约会的副本user2 我有冒充权 我要编辑user2预约的副本 我怎样才能获得user2 s copy 您可以使用 PidLidClean
  • 修改代码以从 Windows 中的 PE 可执行文件检索双重签名信息?

    我已经挣扎了一段时间想要修改这段代码示例 https support microsoft com en us help 323809 how to get information from authenticode signed execu
  • 未找到 _sqlite3_open 等符号错误

    您好 我收到此错误 Undefined symbols sqlite3 open referenced from main in ccRlWVer o sqliite3 close referenced from main in ccRlW
  • 为什么调试器只显示数组指针中的一个元素?

    首先 我知道new是执行此操作的 C 方法 我只是表明有不止一种方法可以重现此错误 而且两种方法都令人难以置信的令人沮丧 我有两种形式的源文件 我正在尝试调试另一个编程作业 但我并没有寻求帮助 基本上 我正在尝试重新实施set作为一个类 具
  • 如何在 C# 中以编程方式创建柔和的颜色?

    根据所需的颜色数量均匀分布地生成它们 如果指定的计数为 8 则看起来像这样 List
  • 如何在 Winform DataGridView 中创建不同的单元格格式

    我有一个 DataGridView 我将其绑定到 DataTable DataTable 是一个全数字值 要求 DataGridView 中的每 n 行都包含文本 而不是数值 以便在视觉上为用户分隔部分 我很高兴在绑定后将此文本数据放入 D
  • 清理堆分配对象的良好实践或约定?

    我正在学习C 我有 C C ObjC 背景 相当高级的语言 在 C 或 ObjC 上 作为函数或方法的结果返回堆分配的对象是很简单的 因为对象的清理是受管理的 按照惯例 会在适当的时候销毁 但我不知道在 C 中应该如何处理这个问题 例如 s
  • 从 STL 列表中删除项目

    我想创建一个函数 如果符合特定条件 则将项目从一个 STL 列表移动到另一个列表 这段代码不是这样做的方法 迭代器很可能会被擦除 函数失效并导致问题 for std list
  • 如何在用户空间程序中使用内核 libcrc32c (或相同的函数)?

    我想在我自己的用户空间程序中进行一些 CRC 检查 我发现内核加密库已经在系统中 并且支持 SSE4 2 我尝试直接 include

随机推荐

  • java 动态代理

    动态代理 这里讲解jdk 动态代理 不讲解cglib动态代理 使用jdk 的InvocationHandler接口与Proxy类实现动态代理 自定义InvocationHandler接口与Proxy类 自定义实现 分析 我们想要实现动态代理
  • dcdc升压计算器excel_优秀DCDC升压

    Figure 1 Basic Application Circuit GENERAL DESCRIPTION The MT3608 is a constant frequency 6 pin SOT23 current mode step
  • pycharm简单使用(Mac):创建一个helloWord

    说明 VSCode是一款轻量级的开发工具 可以支持多款插件这个学习使用确实是一个好的工具 PyCharm是一款Python专门支持的IDE 为什么这里要使用PyCharm呢 PyCharm支持断点调试 1 第一步 创建一个项目 2 第二步
  • CUDA 基础 01 - 概念

    最近在GPU编译器测试方面遇到一些瓶颈 准备学习下cuda 相关的基础知识 warp sm index grid等 CPU VS GPU GPU最重要的一点是可以并行的实现数据处理 这一点在数据量大 运算复杂度不高的条件下极为适用 可以简单
  • 3 Ubuntu上使用Qt运行多线程,设置程序自启动及保护脚本

    Ubuntu上使用Qt运行多线程 设置程序自启动及保护脚本 多线程 自启动及保护脚本 自启动及保护脚本 结束自启动脚本 脚本程序简单说明 设置自启动 多线程 使用多线程时我们需要加入 include lt thread gt 这个头文件包含
  • 区块链常见的几大共识机制

    区块链技术被广泛应用于许多领域 其中共识机制是构成区块链系统的核心部分 共识机制是指用来维护区块链数据一致性 安全性和可靠性的机制 常见的区块链共识机制有以下几种 1 工作量证明 Proof of Work 是最早的共识机制 它将矿工通过解
  • 毕业设计-基于机器视觉的交通标志识别系统

    目录 前言 课题背景和意义 实现技术思路 一 交通标志识别系统 二 交通标志识别整体方案 三 实验分析 四 总结 实现效果图样例 最后 前言 大四是整个大学期间最忙碌的时光 一边要忙着备考或实习为毕业后面临的就业升学做准备 一边要为毕业设计
  • 开源项目Tinyhttp项目源码详解

    HTTP协议 http协议叫做超文本传输协议 是基于tcp ic协议的应用层协议 具体内容可以借鉴这一篇博客 https blog csdn net qq 36894974 article details 103930478 本文主要涉及T
  • [人工智能-深度学习-33]:卷积神经网络CNN - 常见分类网络- LeNet网络结构分析与详解

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 https blog csdn net HiWangWenBing article details 120893764 目录 第1章 卷积神
  • Ubuntu14.04安装配置NFS用于挂载嵌入式文件系统

    Ubuntu14 04安装配置NFS用于挂载嵌入式文件系统 1 安装 sudo apt get install nfs kernel server rpcbind 2 配置 vi etc exports 在文件的最后一行加上 yaffs2
  • 获取随机位数阿拉伯数字

    int Math random 9 1 1000 这里是随机4位数 需要几位数 就乘以几个零 int Math random 9 1 100 随机3位数 int Math random 9 1 10 随机2位数 来个方法吧 获取随机位数的阿
  • IPSec 基础介绍

    IPSec是IETF Internet Engineering Task Force 制定的一组开放的网络安全协议 它并不是一个单独的协议 而是一系列为IP网络提供安全性的协议和服务的集合 包括认证头AH Authentication He
  • python TimedRotatingFileHandler 配置参数 (转)

    TimedRotatingFileHandler这个模块是满足文件名按时间自动更换的需求 这样就可以保证日志单个文件不会太大 用法很简单 示例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 impo
  • python学习之【模块】

    前言 上一篇文章 python学习之 深拷贝 中学习了python中的深浅拷贝学习内容 这篇文章接着学习python中的模块 什么是模块 在python中 一个文件 以 py 为后缀名的文件 就叫做一个模块 每一个模块在python里都被看
  • 群晖做网页服务器_群晖NAS软件DS get介绍及使用方法教程

    我的NAS介绍第二篇 群晖NAS软件介绍与应用之DS get篇前言 1 为什么选择NAS之所以我现在建议大家选择NAS 不仅仅因为网盘的不稳定性和不安全性 遇到和谐大神不说 网盘也经历了各种风风雨雨 从和谐到倒闭不过一步之遥 大家都懂的 还
  • Mysql-连接https域名的Mysql数据源踩的坑

    背景介绍 大家在实际项目中 大部分都会用到关系数据库mysql 通常数据库服务器提供的都是ip的方式 所以不会出现本文涉及到的https域名的问题 本文介绍的是基于数据库服务器是分配了指定域名且有ssl证书的https 连接数据源 遇到的问
  • java面向对象基础练习--实现简单的图书管理系统

    这个系统使用的是java的基础语法 没有使用数据库 实现图书管理系统基础的查询 增加 删除 借阅 归还 打印 退出功能 这个小项目作为我java基础语法的综合运用 主要是为了建立面向对象编程的思想 培养编程习惯 如果有错误或者更好的实现方法
  • 深入详解ThreadLocal

    本文已收录至GitHub 推荐阅读 Java随想录 微信公众号 Java随想录 原创不易 注重版权 转载请注明原作者和原文链接 文章目录 什么是ThreadLocal ThreadLocal 原理 set方法 get方法 remove方法
  • 又回来了

    又回来了 一年多没有来了 再次回来还是感觉那么熟悉 那么亲切 怀念以前在学校的日子 怀念苦苦思索技术的日子 除了学习没有繁杂的社会关系要处理 单纯快乐着 为了一个小小的技术难题 愿意不吃不喝去摸索 去测试 在成功的那一刻忘记了一切疲倦和劳累
  • c++ 实现数据库连接池

    c 实现数据库连接池 自己尝试用c 新标准实现了数据库连接池 代码简化了很多 思路 将数据库的连接当作一个对象添加进list队列中 在连接池创建的时候就建立好队列 并添加自定义大小的连接对象 连接对象用智能指针来管理 现代c 中不应该出现d