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