1. 程式人生 > >[C++]MYSQL 資料庫操作封裝及連線池實現

[C++]MYSQL 資料庫操作封裝及連線池實現

Database類為單例類、執行緒安全、實現了連線池,並且封裝所需要的操作。

本程式碼在Ubuntu下測試可用,使用Mysql connector c++連線資料庫,並啟用C++11特性。

基本操作如下:

//資料庫配置
DbSetting setting;

setting.host = "tcp://127.0.0.1:3306/dbname";
setting.username = "root";
setting.password = "root";
setting.connpoolsize = 100;//連線池最大大小
setting.reconnmaxsize = 3;//重連次數

//初始化
Database::Create(setting);

//呼叫,如果有錯誤會丟擲異常
try { //呼叫封裝好的資料庫操作 Database::GetInstance()->AddUser("deviceid","username"); }catch(const exception& e) {//異常處理 } //銷燬 Database::Destory();

乾貨如下:

標頭檔案:

#ifndef DATABASE_H
#define DATABASE_H
//base
# include <iostream>
# include <pplx/pplx.h>
# include <memory>
# include <map>
# include <functional> # include <list> # include <string> # include <sstream> //mysql # include <cppconn/connection.h> # include <cppconn/driver.h> # include <cppconn/statement.h> # include <cppconn/prepared_statement.h> # include <cppconn/metadata.h>
# include <cppconn/exception.h> using namespace std; using namespace sql; //資料庫配置 struct DbSetting { string host; string username; string password; int connpoolsize;//連線池最大大小 int reconnmaxsize;//重連次數 }; class Database : public enable_shared_from_this<Database> { protected: //單例 static shared_ptr<Database> m_database; public: //建立 static void Create(DbSetting setting); //銷燬 static void Destory(); //獲取例項 static inline shared_ptr<Database> GetInstance(){return m_database;} public: Database(DbSetting setting); ~Database(); private: mutex m_mtDriver; mutex m_mtPool; DbSetting m_setting; Driver* m_driver; //未使用的連線 list<Connection*> m_disableConn; //正在使用的連線 list<Connection*> m_enableConn; private: //初始化 void Init(); //獲取一個連線 Connection* Get(); //釋放一個連線 void Release(Connection*& conn); //建立一個連線 Connection* Create(); //銷燬一個連線 void Destory(Connection*& conn); //銷燬所有連線 void DestoryAll(); public: //封裝的資料庫操作,對於該資料庫的操作,都可按照此方法來實現 void AddUser(string deviceid, string username); }; #endif // DATABASE_H

原始檔:

#include "database.h"

shared_ptr<Database> Database::m_database = nullptr;

void Database::Create(DbSetting setting)
{
    try
    {
        m_database = make_shared<Database>(setting);
        m_database->Init();
    }
    catch (const exception& e)
    {
        std::stringstream ostr;
        ostr << "[db]" << e.what();
        throw runtime_error(ostr.str());
    }
}

void Database::Destory()
{
    m_database.reset();
}

Database::Database(DbSetting setting)
{
    //get setting
    m_setting = setting;
}

Database::~Database()
{
    DestoryAll();
}

void Database::Init()
{
    unique_lock<std::mutex> lck(m_mtDriver);

    m_driver = get_driver_instance();
}

Connection *Database::Get()
{
    unique_lock<std::mutex> lck(m_mtPool);
    Connection* conn = nullptr;

    try
    {
        //當前重連次數
        int reconnCnt = 0;
        do
        {
            if (0 < m_disableConn.size())
            {//存在未使用的連線
                conn = m_disableConn.front();//獲取
                m_disableConn.pop_front();//從未使用連線的池中移除
            }
            else
            {//沒有未使用的連線
                conn = Create();//建立一個連線
            }

            if (nullptr != conn && conn->isValid())
            {//連線有效
                m_enableConn.push_back(conn);//放入正在使用連線的池中
                break;
            }

            //連線無效,銷燬
            Destory(conn);

            //重連次數增加
            reconnCnt++;

        } while (reconnCnt < m_setting.reconnmaxsize);//判斷是否在可重連次數範圍內

        if (nullptr == conn)
        {//connection is invaild excption
            //獲取到的連線無效,則丟擲異常
            throw runtime_error("[db]connection is invaild.");
        }
    }
    catch (const exception& e)
    {
        //銷燬連線
        Destory(conn);

        std::stringstream ostr;
        ostr << "[db]" << e.what();
        throw runtime_error(ostr.str());
    }

    //返回連線
    return conn;
}

void Database::Release(Connection *&conn)
{
    unique_lock<std::mutex> lck(m_mtPool);

    if(nullptr == conn)
    {//連線不為空
        return;
    }

    if(m_disableConn.size() >= m_setting.connpoolsize)
    {//未使用連線已達連線池上限,則刪除
        Destory(conn);
        return;
    }

    if(!conn->isValid())
    {//連線無效,則刪除
        Destory(conn);
        return;
    }

    //否則放入未使用連線的池中
    m_disableConn.push_back(conn);
}

Connection *Database::Create()
{
    unique_lock<std::mutex> lck(m_mtDriver);

    Connection* conn = nullptr;

    try
    {
        //建立一個連線
        conn = m_driver->connect(m_setting.host, m_setting.username, m_setting.password);
    }
    catch (const exception& e)
    {
        std::stringstream ostr;
        ostr << "[db]" << e.what();
        throw runtime_error(ostr.str());
    }

    return conn;
}

void Database::Destory(Connection *&conn)
{//銷燬一個連線
    if (nullptr == conn)
    {
        return;
    }

    delete(conn);
    conn = nullptr;
}

void Database::DestoryAll()
{//銷燬所有連線
    unique_lock<std::mutex> lck(m_mtPool);

    //銷燬未使用連線的池
    for(Connection*& conn : m_disableConn)
    {
        Destory(conn);
    }

    //銷燬正在使用連線的池
    for(Connection*& conn : m_enableConn)
    {
        Destory(conn);
    }
}

//db operations =====================================================================

//資料庫操作範例
void Database::AddUser(string deviceid, string username)
{
    try
    {
        shared_ptr<Connection> conn(Get(), [this](Connection* ptr){Release(ptr);});

        shared_ptr<PreparedStatement> stmt;
        shared_ptr<ResultSet> res;

        stmt.reset(conn->prepareStatement(
                       "call adduser(?,?)"));

        stmt->setString(1, deviceid.c_str());
        stmt->setString(2, username.c_str());

        res.reset(stmt->executeQuery());


        if (1 < res->rowsCount())
        {
            throw new runtime_error("call adduser result is more than 1.");
        }

        for (;;)
        {
            while (res->next()) {
                int errcode = res->getInt("errcode");
                if (errcode != 0)
                {
                    std::stringstream ostr;
                    ostr << "call adduser error code : " << errcode;
                    throw runtime_error(ostr.str());
                }
                return;
            }

            if (stmt->getMoreResults())
            {
                res.reset(stmt->getResultSet());
                continue;
            }
            break;
        }
    }
    catch (const exception& e)
    {
        std::stringstream ostr;
        ostr << "[db]" << e.what();
        throw runtime_error(ostr.str());
    }
}

這裡寫圖片描述