C++ 基于mysql原生api数据库连接池的实现

一:思路

1:连接池中至少保存有最小连接数的数据库连接。当连接数达到最大值的时候,无法再创建新的连接,如果需要获取一个连接,则需要等待相对应的时间。
2:连接池中数据库连接接口基于上篇文章封装的Connection的实现,主要是实现对mysql原生api的封装。
文章链接:
c++ mysql数据库操作api接口的封装

二:实现

首先连接池是单例的,所以封装下单例模式。

Singleton.hpp

/**
 * 单例模式的封装类
 * @tparam T
 */
template<typename T>
class Singleton {
public:
    static T *getInstance() {
        static T t;
        return &t;
    }
};

然后再实现数据库连接池。

ConnectionPool.hpp

#include "Singleton.hpp"
#include <queue>
#include <mutex>
#include <condition_variable>
#include "Connection.hpp"
//#include <thread>

/**
 * 数据库连接池
 */
class ConnectionPool : public Singleton<ConnectionPool> {
private:
    std::queue<std::shared_ptr<Connection>> connections;//所有的连接对象
    std::mutex mutex;//互斥锁
    std::condition_variable conditionVariable;//条件变量

    std::once_flag onceFlag;//执行一次标志
    int maxWaitTime = 10;//最大等待时间毫秒
    int minConnectionNum = 10;//最小连接数
    int maxConnectionNum = 20;//最大连接数
    int currentConnectionNum = 0;//当前池中的连接数

public:
    ConnectionPool(const ConnectionPool &) = delete;

    ConnectionPool &operator=(const ConnectionPool &) = delete;

    ConnectionPool() = default;

    /**
     * 内部初始化函数
     */
    void initInternal() {
        std::call_once(onceFlag, [this]() {
            //初始化数据库最小连接数
            for (int i = 0; i < this->minConnectionNum; ++i) {
                auto connection = createConnection();
                if (connection) {
                    this->connections.push(connection);
                }
            }
        });
    }

    /**
    * 获取一个数据库连接
    * @return
    */
    std::shared_ptr<Connection> getConnection() {
        std::unique_lock<std::mutex> lock(mutex);//加上互斥锁
//        std::cout << "[connection] " << currentConnectionNum << " [this_thread] " << std::this_thread::get_id()
//                  << std::endl;
        std::shared_ptr<Connection> connection = nullptr;
        //移除无效连接
        //若连接已经没用了,ping不通了,直接关闭连接,并移除出队列
        while (!connections.empty() && !connections.front()->ping()) {
            connections.front()->close();//关闭无效连接
            connections.pop();//弹出队
            currentConnectionNum--;
        }

        //进行一番尝试之后,接下来,如果队列不为空,则队首连接是有效连接
        if (!connections.empty()) {
            return popConnection();
        }

        //接下来是队列为空的情况
        //判断是否已经大于最大连接数
        if (currentConnectionNum < maxConnectionNum) {
            //若当前的连接数还没到最大连接数,则创建新的连接
            return createConnection();
        }

        //接下来当前连接数已经达到最大连接数了,无法创建更多的连接,等待一定的时间
        //只有当pred条件为false时调用wait(),才会阻塞当前线程
        if (!conditionVariable.wait_for(lock, std::chrono::milliseconds(maxWaitTime), [this]() {
            return !connections.empty();
        })) {
            //timeout
            std::cerr << "wait for a connection timeout!!" << std::endl;
            return connection;
        }
        //等待成功了,则获取到那个最新的连接
        return popConnection();
    }


    /**
     * 创建一个连接
     * @return
     */
    std::shared_ptr<Connection> createConnection() {
        auto connection = std::make_shared<Connection>();
        if (!connection->connect()) {
            return nullptr;
        }
        //记上当前连接数
        currentConnectionNum++;
        //连接上,返回
        return connection;
    }


    /**
     * 释放数据库连接
     * @param connection
     */
    void releaseConnection(std::shared_ptr<Connection> connection) {
        if (connection != nullptr) {
            std::unique_lock<std::mutex> lock(mutex);//加上互斥锁
            connections.push(connection);
            conditionVariable.notify_one();//释放互斥锁,通知等待线程
        }
    }

private:

    /**
     * 弹出一个连接,并返回
     * @return
     */
    std::shared_ptr<Connection> popConnection() {
        if (connections.empty()) {
            return nullptr;
        }
        auto connection = connections.front();
        connections.pop();
        return connection;
    }
};

三:后续

后续实现orm

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值