c++ 实现数据库连接池

来源:互联网 发布:java web 2年水平 编辑:程序博客网 时间:2024/05/17 22:22

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();}//得到连接池大小intConnectionPool::getPoolSize(){    return conList.size();}//增加连接voidConnectionPool::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));    }}//初始化连接池voidConnectionPool::initConnectPool(int initialSize){    //加锁,增添一个连接    std::lock_guard<std::mutex> locker(lock);    addConn(initialSize);}//销毁一个连接voidConnectionPool::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();    }}//扩大连接池voidConnectionPool::expandPool(int size){    std::lock_guard<std::mutex> locker(lock);    addConn(size);    poolSize += size;}//缩小连接池voidConnectionPool::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;}//归还一个连接voidConnectionPool::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等。

1 0
原创粉丝点击