c++ 实现数据库连接池

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等。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-11 01:34:56

c++ 实现数据库连接池的相关文章

数据库连接池

声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权:凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记. 数据库连接池简介: 数据库连接对象是有限资源,所以数据库连接池是用于负责分配.管理和释放数据库连接对象,它允许应用程序重复使用一个现有的数据库连接对象,而不是再重新建立一个:这一点实际上和线程池的概念差不多.数据库连接池会释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏,这项技术能明显提高对数据库操作的性能. 不使用

JDBC数据库连接池技术

在JDBC中,获得连接或释放资源是非常消耗系统资源的两个过程,为了解决此类性能问题,通常采用连接池技术,来共享连接.这样我们就不需要每次都创建连接.释放连接了,这些操作都交给了连接池. 用池的概念来管理Connection,这样可以重复使用Connection.有了连接池以后就不用自己亲自创建连接而是通过连接池来获得Connection对象.当使用完Connection之后,调用Connection的close()方法不是真的将连接关闭,而是把Connection归还给连接池.连接池就可以继续保

Druid数据库连接池两种简单使用方式

阿里巴巴推出的国产数据库连接池,据网上测试对比,比目前的DBCP或C3P0数据库连接池性能更好 简单使用介绍 Druid与其他数据库连接池使用方法基本一样(与DBCP非常相似),将数据库的连接信息全部配置给DataSource对象. 下面给出2种配置方法实例: 1. 纯Java代码创建 DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName("com.mysql.jdbc.Driver&qu

几种常见数据库连接池的使用比较

感觉在介绍之前有必要阐述一下连接池的几个概念,有助于后边一些文字的理解. 最原始的数据库使用就是打开一个连接并进行使用,使用过后一定要关闭连接释放资源.由于频繁的打开和关闭连接对jvm包括数据库都有一定的资源负荷,尤其应用压力较大时资源占用比较多容易产生性能问题.由此使用连接池的作用就显现出来,他的原理其实不复杂:先打开一定数量的数据库连接,当使用的时候分配给调用者,调用完毕后返回给连接池,注意返回给连接池后这些连接并不会关闭,而是准备给下一个调用者进行分配.由此可以看出连接池节省了大量的数据库

数据库连接池配置说明

1. 引言 1.1 定义 数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库连接池正是针对这个问题提出来的. 数据库连接池负责分配.管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个:释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏.这项技术能明显提高对数据库操作的性能. 1.2 参考资料 DBC

数据库连接池的理解和使用

一.什么是数据库连接池? 官方:数据库连接池(Connection pooling)是程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的连接进行申请,使用,释放. 个人理解:创建数据库连接是一个很耗时的操作,也容易对数据库造成安全隐患.所以,在程序初始化的时候,集中创建多个数据库连接,并把他们集中管理,供程序使用,可以保证较快的数据库读写速度,还更加安全可靠. 二.数据库连接池的运行机制 (1) 程序初始化时创建连接池 (2) 使用时向连接池申请可用连接 (3) 使

数据库连接池和connection的理解

数据库连接池Data Source Pool的理解 1.数据库连接池允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个连接,避免了每个方法里new connection的耗费资源和时间. 2.数据库连接池是在项目启动时候初始化的,以方便程序运行时,随时可以调用这些已经被创建好的connection.只需要getConnection()就好. connection的建立.断开都由连接池自身来管理. 3.创建connection是个很耗时的操作,所以建议在项目启动的时候去创建connec

关于c3p0数据库连接池的简单使用

在使用开发基于数据库的web程序时,传统的模式基本是按以下步骤: 在主程序(如servlet.beans)中建立数据库连接. 进行sql操作 断开数据库连接. 这种模式开发,存在的问题: 普通的JDBC数据库连接使用 DriverManager 来获取,每次向数据库建立连接的时候都要将 Connection 加载到内存中,再验证用户名和密码(得花费0.05s-1s的时间).需要数据库连接的时候,就向数据库要求一个,执行完成后再断开连接.这样的方式将会消耗大量的资源和时间.数据库的连接资源并没有得

DBCP数据库连接池的简单使用

0.DBCP简介      DBCP(DataBase connection pool)数据库连接池是 apache 上的一个Java连接池项目.DBCP通过连接池预先同数据库建立一些连接放在内存中(即连接池中),应用程序需要建立数据库连接时直接到从接池中申请一个连接使用,用完后由连接池回收该连接,从而达到连接复用,减少资源消耗的目的. 1.DBCP所依赖的jar包(以下例子基于如下jar包版本)    commons-dbcp2-2.1.1.jar       commons-logging-

Spring数据库连接池 c3p0、dbcp、spring-jdbc

在用dbcp的时候 后面加上 destroy-method="close" 销毁的方法没事 但是用 spring的jdbc就会报错 提示找不到close这个方法  这是为什么? DBCP DBCP(DataBase connection pool),数据库连接池.是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件.单独使用dbcp需要2个包:commons-dbcp.jar,commons-pool.jar由于建立数据库连接是一个非常耗时耗资源的行为