MySql数据库连接池

项目场景:

单例模式,并能正确地析构。智能指针的使用。


connection_pool.h

/*
 *File: connection_pool.h
 *Author: fengwei
 */

#ifndef _CONNECTION_POOL_H  
#define _CONNECTION_POOL_H  

#include <mysql/jdbc.h>
#include <windows.h>  
#include <list>  
#include <iostream>
using namespace std;
using namespace sql;
/*通过写一个加锁的类来对共享的数据进行有效的安全控制,防止内存错误*/
class MTCMutex
{
public:
    MTCMutex() :_mutex(NULL)
    {
        this->_mutex = CreateMutex(NULL, FALSE, NULL);
        if (this->_mutex == NULL)
            throw std::exception("CreateMutex 失败!");
    }
    virtual ~MTCMutex()
    {
        if (this->_mutex)
        {

            CloseHandle(this->_mutex);
            std::cout << "mutex" << std::endl;
            this->_mutex = NULL;
        }
    }
    MTCMutex(const MTCMutex& mutex) { *this = mutex; }
    MTCMutex& operator=(const MTCMutex& other)
    {
        if (this != &other)
        {
            this->_mutex = other._mutex;
        }
        return *this;
    }
private:
    HANDLE _mutex;


public:
    BOOL Lock()
    {
        DWORD dwRet = ::WaitForSingleObject(this->_mutex, INFINITE);
        if (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_ABANDONED)
            return TRUE;
        else
            return FALSE;
    }


    void UnLock()
    {
        ReleaseMutex(this->_mutex);
    }
};
class ConnPool {
private:
    int curSize; //当前已建立的数据库连接数量  
    int maxSize; //连接池中定义的最大数据库连接数  
    string username;
    string password;
    string url;
    list<Connection*> connList; //连接池的容器队列  STL list 双向链表
    static MTCMutex lock; //线程锁  
    static ConnPool *connPool;
    Driver*driver;

    Connection*CreateConnection(); //创建一个连接  
    void InitConnection(int iInitialSize); //初始化数据库连接池  
    void DestoryConnection(Connection *conn); //销毁数据库连接对象  
    void DestoryConnPool(); //销毁数据库连接池  
    ConnPool(string url, string user, string password, int maxSize); //构造方法  

    class GGarbo
    {
    public:
        ~GGarbo()
        {
            if (connPool != NULL)
            {
                std::cout << "~GGarbo()" << std::endl;
                delete connPool;
                connPool = NULL;
            }
        }
    };
    static GGarbo bo;
public:
    ~ConnPool();
    Connection*GetConnection(); //获得数据库连接  
    void ReleaseConnection(Connection *conn); //将数据库连接放回到连接池的容器中  
    static ConnPool *GetInstance(); //获取数据库连接池对象  
};
#endif  /*_CONNECTION_POOL_H */  



connection_pool.cpp

#include <stdexcept>
#include <exception>
#include <stdio.h>
#include "connection_pool.h"

using namespace std;
using namespace sql;

ConnPool* ConnPool::connPool = NULL;
MTCMutex ConnPool::lock;
ConnPool::GGarbo ConnPool::bo;

// 获取连接池对象,单例模式
ConnPool* ConnPool::GetInstance()
{
    if (connPool == NULL)
    {
        ConnPool::lock.Lock();
        if (connPool == NULL)
            connPool = new ConnPool("localhost", "root", "123456", 50);
        ConnPool::lock.UnLock();
    }

    return connPool;
}

// 数据库连接池的构造函数
ConnPool::ConnPool(string url, string userName, string password, int maxSize)
{
    this->maxSize = maxSize;
    this->curSize = 0;
    this->username = userName;
    this->password = password;
    this->url = url;

    try
    {
        this->driver = sql::mysql::get_driver_instance();
    }
    catch (sql::SQLException& e)
    {
        perror(e.what());
    }
    catch (std::runtime_error& e)
    {
        perror(e.what());
    }

    // 在初始化连接池时,建立一定数量的数据库连接
    this->InitConnection(maxSize / 2);
}

// 初始化数据库连接池,创建最大连接数一半的连接数量
void ConnPool::InitConnection(int iInitialSize)
{
    Connection* conn;
    ConnPool::lock.Lock();

    for (int i = 0; i < iInitialSize; i++)
    {
        conn = this->CreateConnection();
        if (conn)
        {
            connList.push_back(conn);
            ++(this->curSize);
        }
        else
        {
            throw std::exception("Init connection error.");
        }
    }

    ConnPool::lock.UnLock();
}

// 创建并返回一个连接
Connection* ConnPool::CreateConnection()
{
    Connection* conn;
    try
    {
        sql::ConnectOptionsMap connection_properties;

        connection_properties[OPT_HOSTNAME] = this->url;
        connection_properties[OPT_USERNAME] = this->username;
        connection_properties[OPT_PASSWORD] = this->password;
        connection_properties[OPT_CHARSET_NAME] = sql::SQLString("gbk");
        connection_properties[OPT_CHARACTER_SET_RESULTS] = sql::SQLString("gbk");
        // 建立连接
        conn = driver->connect(connection_properties);
        return conn;
    }
    catch (sql::SQLException& e)
    {
        perror(e.what());
        return NULL;
    }
    catch (std::runtime_error& e)
    {
        perror(e.what());
        return NULL;
    }
}

// 从连接池中获得一个连接
Connection* ConnPool::GetConnection()
{
    Connection* con;
    ConnPool::lock.Lock();

    // 连接池容器中还有连接
    if (connList.size() > 0)
    {
        // 获取第一个连接
        con = connList.front();
        // 移除第一个连接
        connList.pop_front();
        // 判断获取到的连接的可用性
        // 如果连接已经被关闭,删除后重新建立一个
        if (con->isClosed())
        {
            delete con;
            con = this->CreateConnection();
            // 如果连接为空,说明创建连接出错
            if (con == NULL)
            {
                // 从容器中去掉这个空连接
                --curSize;
            }
        }

        ConnPool::lock.UnLock();
        return con;
    }
    // 连接池容器中没有连接
    else
    {
        // 当前已创建的连接数小于最大连接数,则创建新的连接
        if (curSize < maxSize)
        {
            con = this->CreateConnection();
            if (con)
            {
                ++curSize;
                ConnPool::lock.UnLock();
                return con;
            }
            else
            {
                ConnPool::lock.UnLock();
                return NULL;
            }
        }
        // 当前建立的连接数已经达到最大连接数
        else
        {
            perror("[GetConnection] connections reach the max number.");
            ConnPool::lock.UnLock();
            return NULL;
        }
    }
}

// 释放数据库连接,将该连接放回到连接池中
void ConnPool::ReleaseConnection(sql::Connection* conn)
{
    static int i= 0;
    if (conn)
    {
        
       
        ConnPool::lock.Lock();
        i++;
        std::cout << "ReleaseConnection次数" << i << std::endl;
        connList.push_back(conn);

        ConnPool::lock.UnLock();
    }
}

// 数据库连接池的析构函数
ConnPool::~ConnPool()
{
    this->DestoryConnPool();
}

// 销毁连接池,需要先销毁连接池的中连接
void ConnPool::DestoryConnPool()
{
    list<Connection*>::iterator itCon;
    ConnPool::lock.Lock();

    for (itCon = connList.begin(); itCon != connList.end(); ++itCon)
    {
        // 销毁连接池中的连接
        this->DestoryConnection(*itCon);
    }
    curSize = 0;
    // 清空连接池中的连接
    connList.clear();

    ConnPool::lock.UnLock();
}

// 销毁数据库连接
void ConnPool::DestoryConnection(Connection* conn)
{
    if (conn)
    {
        try
        {
            // 关闭连接
            conn->close();
        }
        catch (sql::SQLException& e)
        {
            perror(e.what());
        }
        catch (std::exception& e)
        {
            perror(e.what());
        }
        // 删除连接
        delete conn;
    }
}

DWORD WINAPI Fun(LPVOID lp)
{
    std::unique_ptr < Connection, function<void(Connection *)>> con(ConnPool::GetInstance()->GetConnection(), [](Connection *c)->void
    {
        ConnPool::GetInstance()->ReleaseConnection(c);
    }
    );

    for (int i = 0; i < 20; i++)
    {
        std::unique_ptr< Statement> state(con->createStatement());
        //state = con->createStatement();
        state->execute("use test");
        Sleep(500);
        // 查询数据库
        std::unique_ptr<ResultSet> result(state->executeQuery("SELECT * from student"));
        // 打印数据库查询结果
        cout << "================================" << endl;
        while (result->next())
        {
            int nRoleId = result->getInt(1);
            string strOccupation = result->getString(2);
            string strCamp = result->getString(4);
            cout <<"当前线程是"<<GetCurrentThreadId()<<":"<< nRoleId << " , " << strOccupation << " , " << strCamp << endl;
        }
        cout << "i is: " << i << endl;
        cout << "================================" << endl;
    }

    return EXIT_SUCCESS;

}

单例实现:

ConnPool* ConnPool::GetInstance()
{
    //方法一
    /*if (connPool == NULL)
    {
        ConnPool::lock.Lock();
        if (connPool == NULL)
            connPool = new ConnPool("localhost", "root", "123456", 30,3);
        ConnPool::lock.UnLock();
    }*/


    //方法二
    /*static std::once_flag s_flag;
    std::call_once(s_flag, [&]() {
        connPool = new ConnPool("localhost", "root", "123456", 30, 3);
    });*/

    //方法三
    static INIT_ONCE InitOnce = INIT_ONCE_STATIC_INIT;
    InitOnceExecuteOnce(&InitOnce, [](PINIT_ONCE InitOnce, PVOID Parameter, PVOID *context)->BOOL
    {
        connPool = new ConnPool("localhost", "root", "123456", 30, 3);
        return TRUE;

    },
        nullptr, nullptr
        );

    return connPool;

}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值