[C++]MYSQL 資料庫操作封裝及連線池實現
阿新 • • 發佈:2019-01-07
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());
}
}