我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何利用C++实现mysql数据库的连接池详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何利用C++实现mysql数据库的连接池详解

为什么是mysql?

现在几乎所有的后台应用都要用到数据库,什么关系型的、非关系型的;正当关系的,不正当关系的;主流的和非主流的, 大到Oracle,小到sqlite,以及包括现在逐渐流行的基于物联网的时序数据库,比如涛思的TDengine,咱们中国人自己的开源时序数据库,性能杠杠滴。

凡此总总,即使没用过,也听说过,但大部分人或企业用的最多的就是白嫖型数据库:mysql。该数据库的特点就是无论是个人还是企业都能玩的起。像Oracle这种名媛型数据库基本就属于银行特供,银行需要花钱买平安,心里踏实。不买对的,只选贵的,因为人家确实不差钱。

如果你的后台应用连数据库都不需要,那跟咸鱼网站有什么区别呢?就是咸鱼二手网也要用到数据库的。如果一个IT民工一辈子没用过数据库就在35(~45)岁时“被退休”,那他的职业生涯是遗憾的,是不完美的,是不纯粹的。 好歹年轻是也要用一下非主流的Access吧,哪怕Execel也成。这种感觉就好比在大学时没谈过恋爱一样,光忙着羡慕别人就突然毕业了。

为什么要搞资源池?

目前大部分后台程序都选择Java开发或PHP,这两种语言的第三方库非常丰富,丰富到让开发人员的只要将精力放在具体业务上即可。比如数据库的资源池,只要选择好适当的jar包外加配置好相应的数据库参数,即可放心大胆的使用mysql。

当然,如果你命硬的话,也可以选择用C或C++开发后台应用。这时候你就需要自己DIY一个数据库资源池。

如果只是一个客户端程序,基本不需要连接池,但对于后台应用来说,高并发就意味着多线程,多线程程就意味着资源的竞争。内存访问如此,数据库访问也是如此。每次数据库的打开和关闭就是一次网络连接和关闭的过程,频繁的打开和关闭无疑会浪费大量的系统资源。这时候就需要提前建立好N个连接,并放在资源池中并提供给不同线程访问使用。

mysql资源池实现的案例源码

我一直相信好的代码是不需要过的语言来解释的,代码即文档,要啥自行车。以下案例只是一个实现思路,供参考。

头文件:MysqlPool.h


#pragma warning(disable : 4786) 

#include <windows.h>
#include <winsock2.h>
#include <mysql.h>     // 确保你的机器有mysql开发库
#include <vector>
#include <string>
using namespace std;

#define DEFAULT_POOL_SIZE  20 // 缺省mysql连接池中的数量
#define DEFAULT_POOL_TIMEOUT 60 // 获取池中mysql连接的超时

// 自定义数据库查询回调函数
typedef BOOL (CALLBACK *LPFN_RetrieveRecordData)(MYSQL_ROW& sqlRow, MYSQL_FIELD* pSqlFields, int iFieldCount, DWORD dwUserData);

// Mysql数据库连接类
class CMysqlConn
{
public:
 CMysqlConn(const char* pszDBServer, UINT uDBPort, const char* pszDBName, 
    const char* pszDBUser, const char* pszDBPwd);
 virtual ~CMysqlConn();
 
public:
 // 打开/关闭一个mysql连接
 BOOL Open();
 void Close();
 
 // ping连接是否已关闭
 BOOL Ping();
 // 重置字符集
 BOOL ResetCharset();
 
 
public:
 // ================SQL语句操作(简单实现几个)================
 // 查询
 BOOL Select(const char* pszSql, LPFN_RetrieveRecordData lpfnRetrieveRecordData, DWORD dwUserData);
 // 执行
 BOOL Execute(const char* pszSql);
 // 插入,如果主键是自增整型,返回插入后的主键值
 __int64 Insert(const char* pszSql);
 
 
protected:
 MYSQL* m_pMysql;   // mysql数据库操作对象

 // 以下是连接mysql需要的参数
 string m_strDBServer;  // mysql数据库所在服务器
 UINT m_uDBPort;   // mysql数据库连接端口
 string m_strDBName;  // 数据库名称
 string m_strDBUser;  // 数据库账户
 string m_strDBPwd;   // 数据库密码
 
};

// 数据库连接池实现
class CMysqlPool  
{
public:
 CMysqlPool();
 virtual ~CMysqlPool();

 // 创建mysql连接池
 BOOL Create(const char* pszDBServer, UINT uDBPort, const char* pszDBName, 
    const char* pszDBUser, const char* pszDBPwd,
     DWORD dwPoolSize = DEFAULT_POOL_SIZE, 
    DWORD dwTimeOut = DEFAULT_POOL_TIMEOUT);   
 // 销毁连接池
  void Destroy();
  
public:

 // 获取一个mysql连接
  CMysqlConn* Get();

 // 释放一个mysql连接
  void Release(CMysqlConn* pConn);
 
protected:
 HANDLE    m_hSemaphore;       // 信号量句柄
 DWORD    m_dwPoolSize;  // 连接池大小 
 DWORD    m_dwTimeOut;  // 超时,单位秒
 CRITICAL_SECTION m_csPool;   // 连接池锁

 vector<CMysqlConn*> m_vecIdle;   // 闲队列
 vector<CMysqlConn*> m_vecBusy;   // 忙队列
};

实现文件:MysqlPool.cpp


#include "stdafx.h"
#include "MysqlPool.h"
#include <assert.h>
#include <algorithm>

#pragma comment(lib, "libmysql.lib") //连接MysQL需要的库

//////////////////////////////////////////////////////////////////////
// CMysqlConn: mysql数据库连接类
//////////////////////////////////////////////////////////////////////

CMysqlConn::CMysqlConn(const char* pszDBServer, UINT uDBPort, const char* pszDBName, 
      const char* pszDBUser, const char* pszDBPwd)
{
 assert(pszDBServer);
 assert(pszDBName);
 assert(pszDBUser);
 assert(pszDBPwd);

 m_pMysql = NULL;
 m_strDBServer = pszDBServer;
 m_uDBPort = uDBPort;
 m_strDBName = pszDBName;
 m_strDBUser = pszDBUser;
 m_strDBPwd = pszDBPwd;
}

CMysqlConn::~CMysqlConn()
{
 Close();
}

// 打开一个mysql数据库,即建立一个数据库连接
BOOL CMysqlConn::Open()
{
 if(m_pMysql)
 {
  mysql_close(m_pMysql); // 关闭连接 
  m_pMysql = NULL;
 }
 
 m_pMysql = mysql_init(NULL);
 if(!m_pMysql)
  return FALSE;
 
 // 连接数据库
    if(!mysql_real_connect(m_pMysql, m_strDBServer.c_str(), m_strDBUser.c_str(),
       m_strDBPwd.c_str(), m_strDBName.c_str(), m_uDBPort, NULL, 0))
    {
  int i = mysql_errno(m_pMysql);
  const char * pszErr = mysql_error(m_pMysql);

  return FALSE;
 }
 
 // 设置重连
 char chValue = 1;
 mysql_options(m_pMysql, MYSQL_OPT_RECONNECT, &chValue); 
 mysql_query(m_pMysql,"set names 'gbk'"); 
 
 return TRUE;
}

// 关闭数据库连接
void CMysqlConn::Close()
{
 if(m_pMysql)
  mysql_close(m_pMysql); // 断开连接
 m_pMysql = NULL; 
}

// ping一下mysql,看看连接还活着
BOOL CMysqlConn::Ping()
{
 if(m_pMysql)
  return (0 == mysql_ping(m_pMysql));
 return FALSE;
}

// 设置字符集为GBK
BOOL CMysqlConn::ResetCharset()
{
 if(m_pMysql)
  return (0 == mysql_query(m_pMysql, "set names 'gbk'")); 
 return FALSE;
}

// mysql执行:delete 或 update
BOOL CMysqlConn::Execute(const char* pszSql)
{
 assert(pszSql);

 if(!m_pMysql)
  return FALSE;
 
 MYSQL_STMT *myStmt = mysql_stmt_init(m_pMysql);
 if(!myStmt)
 {
  return FALSE;
 }
 
 if(0 != mysql_stmt_prepare(myStmt, pszSql, strlen(pszSql)))
 {
  mysql_stmt_close(myStmt);
  return FALSE;
 }
 if(0 != mysql_stmt_execute(myStmt))
 {
  mysql_stmt_close(myStmt);
  return FALSE;
 }
 mysql_stmt_close(myStmt);
 
 return TRUE;  
}

// mysql插入
__int64 CMysqlConn::Insert(const char* pszSql)
{ 
 assert(pszSql);

 MYSQL_STMT *myStmt = mysql_stmt_init(m_pMysql);
 if(!myStmt)
  return 0;
 
 if(0 != mysql_stmt_prepare(myStmt, pszSql, strlen(pszSql)))
 {
  int i = mysql_errno(m_pMysql);
  const char * s = mysql_error(m_pMysql);
  mysql_stmt_close(myStmt);
  return 0;
 }
 if(0 != mysql_stmt_execute(myStmt))
 {
  mysql_stmt_close(myStmt);
  return 0;
 }
 mysql_stmt_close(myStmt);
 
 __int64 i64ID = mysql_insert_id(m_pMysql); 
 return i64ID;
}

// mysql查询
BOOL CMysqlConn::Select(const char* pszSql, LPFN_RetrieveRecordData lpfnRetrieveRecordData, DWORD dwUserData)
{
 if(!m_pMysql)
  return FALSE;
 
 if(NULL == lpfnRetrieveRecordData)
  return FALSE;
 
 if(0 != mysql_real_query(m_pMysql, pszSql, strlen(pszSql)))
 {
  return FALSE; 
 }
 
 MYSQL_RES *resRecord = mysql_store_result(m_pMysql);
 int iFieldCount = resRecord->field_count;
 
 MYSQL_ROW sqlRow;
 while (sqlRow = mysql_fetch_row(resRecord))
    {
  if(!lpfnRetrieveRecordData(sqlRow, resRecord->fields, iFieldCount, dwUserData))
   break;
 }
 mysql_free_result(resRecord);
 return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CMysqlPool: mysql数据库连接池类
//////////////////////////////////////////////////////////////////////

CMysqlPool::CMysqlPool()
{
 ::InitializeCriticalSection(&m_csPool);
}

CMysqlPool::~CMysqlPool()
{
 Destroy();
 ::DeleteCriticalSection(&m_csPool);
}

// 创建mysql连接池
BOOL CMysqlPool::Create(const char* pszDBServer, UINT uDBPort, const char* pszDBName, 
      const char* pszDBUser, const char* pszDBPwd,
      DWORD dwPoolSize, DWORD dwTimeOut)
{
 m_dwTimeOut = dwTimeOut;
 m_dwPoolSize = dwPoolSize;
 
 // 创建信号量
 m_hSemaphore = ::CreateSemaphore(NULL, dwPoolSize, dwPoolSize, NULL);
 if (NULL == m_hSemaphore)
 {
  return FALSE;
 }
 
 // 创建数据库连接池
 for(DWORD i = 0; i < dwPoolSize; ++i)
 {
  // 创建一个mysql数据库连接
  CMysqlConn *pConn = new CMysqlConn(pszDBServer, uDBPort, pszDBName, pszDBUser, pszDBPwd);
  if(!pConn->Open()) 
  {
   delete pConn;
   continue;
  }
  m_vecIdle.push_back(pConn);
 }

 return m_vecIdle.size() > 0;
 
}

// 销毁mysql连接池
void CMysqlPool::Destroy()
{
 ::CloseHandle(m_hSemaphore);
 m_hSemaphore = NULL;
 
 // 释放idle队列
 vector<CMysqlConn*>::iterator it;
    for(it = m_vecIdle.begin(); it != m_vecIdle.end(); ++it)
 {
  CMysqlConn* pConn =  *it;
  delete pConn;
 }
 m_vecIdle.clear();
 
 // 释放busy队列
 while(!m_vecBusy.empty())
 {
  CMysqlConn* pConn =  m_vecBusy.back();
  m_vecBusy.pop_back();
  delete pConn;
 } 
}

// 从mysql连接池获取一个连接
CMysqlConn* CMysqlPool::Get()
{
 DWORD dwRet = ::WaitForSingleObject(m_hSemaphore, m_dwTimeOut*1000);
 
 if (WAIT_OBJECT_0 != dwRet)    // 超时,说明资源池没有可用mysql连接
 {
  printf("数据库没有可用连接。\r\n");
  return NULL;
 }
 
 // 从连接池中获取一个闲置连接
 CMysqlConn* pConn = NULL;

 ::EnterCriticalSection(&m_csPool);

  if (!m_vecIdle.empty())
  {
  pConn = m_vecIdle.back();   // 移出idle队列
   m_vecIdle.pop_back(); 
   m_vecBusy.push_back(pConn);   // 加入busy队列
  }
 ::LeaveCriticalSection(&m_csPool);
 
 if(NULL == pConn)
  return NULL;
 
 // 如果一个连接长时间无通信,可能被防火墙关闭,此时可以通过mysql_ping函数测试一下
 // 本例中通过重新设置字符集
 // 重新设置字符集,并判断数据库连接是否已断开
 if(!pConn->ResetCharset())   
 {
  if(!pConn->Open())
   return NULL;
 }
 
 printf("==》资源池:记得还我哦。\r\n");
 return pConn;
}

// 释放一个连接到mysql连接池
void CMysqlPool::Release(CMysqlConn* pConn)
{
 if(NULL == pConn)
  return;
 
 // 释放一个信号量
 ::ReleaseSemaphore(m_hSemaphore, 1, NULL); 

 ::EnterCriticalSection(&m_csPool);

 // 从Busy队列中释放该连接
 vector<CMysqlConn*>::iterator it = find(m_vecBusy.begin(), m_vecBusy.end(), pConn);
 if(it != m_vecBusy.end())
 {
  printf("POOL SIZE : %d, %d\r\n", m_vecIdle.size(), m_vecBusy.size());
  m_vecBusy.erase(it);    // 移出busy队列
  m_vecIdle.push_back(pConn);   // 加入idle队列
  printf("POOL SIZE : %d, %d\r\n", m_vecIdle.size(), m_vecBusy.size());
 }
 ::LeaveCriticalSection(&m_csPool);
 
 printf("《==资源池说:有借有还再借不难,常来玩啊。\r\n");
}

测试函数


void TestMysqlPool()
{
 // 创建mysql连接资源池
 CMysqlPool mysqlPool;
 if(!mysqlPool.Create("127.0.0.1", 3306, "information_schema", "root", "123456"))
 {
  printf("Create mysql conneticon pool failed.\r\n");
  return;
 }

 // 从资源池中获取一个连接,连接池说:记得要还哦!
 CMysqlConn* pConn = mysqlPool.Get();

 // 假装做一次数据库操作
 char* pszSQL =  "SELECT * FROM CHARACTER_SETS";
 pConn->Select(pszSQL, RetrieveRecordData, 0);

 // 将连接还给资源池并谢谢!连接池说:不客气!
 mysqlPool.Release(pConn);

 printf("Test over.\r\n");
}

输出打印

总结

到此这篇关于如何利用C++实现mysql数据库连接池的文章就介绍到这了,更多相关C++实现mysql连接池内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

如何利用C++实现mysql数据库的连接池详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

如何用C++自己实现mysql数据库的连接池?

为什么是mysql?现在几乎所有的后台应用都要用到数据库,什么关系型的、非关系型的;正当关系的,不正当关系的;主流的和非主流的, 大到Oracle,小到sqlite,以及包括现在逐渐流行的基于物联网的时序数据库,比如涛思的TDengine,咱们中国人自己的开
如何用C++自己实现mysql数据库的连接池?
2015-05-02

Python实现Mysql数据库连接池实例详解

python连接Mysql数据库:Python编程中可以使用MySQLdb进行数据库的连接及诸如查询/插入/更新等操作,但是每次连接MySQL数据库请求时,都是独立的去请求访问,相当浪费资源,而且访问数量达到一定数量时,对mysql的性能会
2022-06-04

基于C++实现Mysql数据库连接池实例

目录项目技术点项目意义项目实现Connection设计ConnectionPool设计项目复杂接口细节刨析项目技术点C语言进行mysql数据库编程无锁单例基于STL队列加C++11新特性保证线程安全实现的生产者消费者模型C++11多线程编
2022-12-07

项目之C++如何实现数据库连接池

这篇文章主要介绍了项目之C++如何实现数据库连接池问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-03-23

java数据库连接池如何实现

Java数据库连接池可以通过以下步骤实现:1. 导入相应的依赖库:你需要导入数据库驱动程序和连接池的相关依赖库。一般来说,你需要使用特定数据库供应商提供的JDBC驱动程序,并选择一个连接池实现(如Apache Commons DBCP、Hi
2023-09-16

数据库连接池的原理?连接池使用什么数据结构实现?实现连接池?

早期我们怎么进行数据库操作呢?1、原理:一般来说,Java应用程序访问数据库的过程是:加载数据库驱动程序;通过jdbc建立数据库连接;访问数据库,执行SQL语句;断开数据库连接。2、代码 1 //查询所有用户 2 Public void FindAllUser
数据库连接池的原理?连接池使用什么数据结构实现?实现连接池?
2015-09-26

使用druid如何实现配置数据库连接池

本篇文章为大家展示了使用druid如何实现配置数据库连接池 ,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。druid的配置项如下配置缺省值说明name 配置这个属性的意义在于,如果存在多个数据源,监
2023-05-31

使用Spring Boot如何实现集成Druid数据库连接池

使用Spring Boot如何实现集成Druid数据库连接池?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1. 前言Druid数据库连接池由阿里巴巴开源,号称是java语言
2023-05-31

详解springboot 使用c3p0数据库连接池的方法

使用springboot开发时,默认使用内置的tomcat数据库连接池,经常碰到这种情况:运行时间一长,数据库连接中断了。所以使用c3p0连接池吧。引入的maven依赖: c3p0
2023-05-31

如何实现php和mysql数据库连接

本篇内容介绍了“如何实现php和mysql数据库连接”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1.安装和配置MySQL数据库在开始MyS
2023-07-05

springboot使用alibaba的druid数据库连接池错误如何解决

本篇内容介绍了“springboot使用alibaba的druid数据库连接池错误如何解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!使用
2023-07-05

使用java如何实现连接数据库

今天就跟大家聊聊有关使用java如何实现连接数据库,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。package com.shsxt.jdbcs;import java.sql.Con
2023-05-31

详解如何使用Node.js连接数据库ORM

这篇文章主要为大家介绍了详解如何使用Node.js连接数据库ORM示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-12-19

编程热搜

目录