MYSQL--连接池

chunfeng— 2025-04-10 11:32:26

 1.什么数据库连接池

        MySQL 连接池本质上是一个数据库连接的缓存容器。 

2.数据库连接池解决了什么问题

        2.1 提高性能:通过复用连接池中的连接,避免了重复的连接创建过程,大大缩短了数据库操作的响应时间,在高并发场景下,显著提升了系统的整体性能。

        2.2 减少资源浪费:不再频繁创建和销毁连接,降低了系统资源的消耗。

        2.3 提升应用稳定性:连接池可以对连接进行统一管理,当出现连接泄漏(即应用程序获取连接后未正确归还)等问题时,连接池能够进行一定程度的检测和处理,避免因连接问题导致应用程序崩溃,从而提升了应用的稳定性。

3.怎么解决的

        它在系统初始化时创建一定数量的数据库连接对象,并将这些连接维护在一个池中。当应用程序需要与 MySQL 数据库进行交互时,无需重新创建新的连接,而是从连接池中获取一个已有的连接;当操作完成后,再将该连接归还到连接池中,以便后续其他请求复用。这种方式大大减少了连接创建和销毁的开销。

4.同步连接池和异步连接池的区别

        4.1 获取返回值

        同步链接(Synchronous): 通过接口的返回值接受数据库返回值,主线程会堵塞。

        异步连接(Asynchronous): 通过回调函数接受数据库返回值,主线程不会堵塞。

        4.2连接流程

                        同步                                                                异步

同步连接

        4.3使用场景

                 4.3.1同步连接池

                    1.配置加载:配置文件写入,系统文件。

                    2.数据初始化:热点数据加载,避免数据库重复访问。

                    3.服务器初始化:服务器主线程初始化。

                4.3.2异步连接池

                     服务器正常启动后,各种操作,耗时查询。    

5.单条MYSQL连接的过程

6.MYSQL的驱动

libmysqlclient     //纯c实现
libmysqlcppconn    //c++实现,使用了异常机制
//阻塞io

 7.连接池的实现

        7.1安装接口库

//安装 libmysqlcppconn
sudo apt-get install libmysqlcppconn-dev

**头文件: /usr/include/cppconn/*.h
**库文件: /uer/lib/x86_64-linux-gnu/
    libmysqlcppconn.a
    libmysqlcppconn.so

        7.2 异步连接

        基于连接去执行命令(send)和等待结果(recv)的过程是一个耗时操作,考虑使用线程池去实现。

        因为线程要获取,命令的返回值结果作为执行命令的参数,所以我们引入future-promise,来获取结果

        主线程创建 promise 并获取 future。
        新线程执行 database_query(),查询完成后调用 prom.set_value(result) 传递查询结果。
        主线程阻塞等待 fut.get() 获取 SQL 查询结果

        7.3代码实现


//MySQLConnPool.h

namespace sql {
    class ResultSet;
}
//前置声明  防止依赖过深
class MySQLConn;
template <typename T>
class BlockingQueue;

class SQLOperation;


class MySQLConnPool {
public:
    //获取单例
    static MySQLConnPool *GetInstance(const std::string &db);

    void InitPool(const std::string &url, int pool_size);
    //输入sql语句,执行对应的回调函数
    QueryCallback Query(const std::string &sql, std::function<void(std::unique_ptr<sql::ResultSet>)> &&cb);

private:
    MySQLConnPool(const std::string &db) : database_(db) {}
    ~MySQLConnPool();

    std::string database_;
    std::vector<MySQLConn *> pool_;
    //因为数据库有多个,但是我们每次只访问一个,所以用单例模式
    //一个数据库对应一个单例,所以用unordered_map存储
    static std::unordered_map<std::string, MySQLConnPool *> instances_;
    //阻塞队列 存储sql操作
    BlockingQueue<SQLOperation *> *task_queue_;
};


//MySQLConn.h

//前置声明
namespace sql 
{
    class Driver;
    class Connection;
    class SQLException;
    class ResultSet;
}

class MySQLWorker;

template <typename T>
class BlockingQueue;

class SQLOperation;

struct MySQLConnInfo {
    explicit MySQLConnInfo(const std::string &info, const std::string &db);
    std::string user;
    std::string password;
    std::string database;
    std::string url;
};

class MySQLConn {
public:
    MySQLConn(const std::string &info, const std::string &db, BlockingQueue<SQLOperation *> &task_queue);
    ~MySQLConn();

    //自定义 连接函数,防止连接中断
    int Open();
    void Close();

    //执行sql语句
    sql::ResultSet* Query(const std::string &sql);

    
private:
    //异常处理函数
    void HandlerException(sql::SQLException &e);
    //sql驱动,连接
    sql::Driver *driver_;
    sql::Connection *conn_;
    //对应的线程对象
    MySQLWorker *worker_;
    
    MySQLConnInfo info_;
};


//MySQLWorker.h

class MySQLConn;

template <typename T>
class BlockingQueue;

class SQLOperation;

class MySQLWorker {
public:
    //传入连接线程,和执行命令队列
    MySQLWorker(MySQLConn *conn, BlockingQueue<SQLOperation *> &task_queue);
    ~MySQLWorker();

    void Start();
    void Stop();

private:
    //工作线程
    void Worker();
    
    MySQLConn *conn_;
    std::thread worker_;
    //任务队列
    BlockingQueue<SQLOperation *> &task_queue_;
};

//SQLOperation.h

namespace sql
{
    class ResultSet;
}

class MySQLConn;

class SQLOperation {
public:
    explicit SQLOperation(const std::string &sql) : sql_(sql) {}
    void Execute(MySQLConn *conn);

    std::future<std::unique_ptr<sql::ResultSet>> GetFuture() {
        return promise_.get_future();
    }

private:
    std::string sql_;
    std::promise<std::unique_ptr<sql::ResultSet>> promise_;
};

//QueryCallback.h

namespace sql
{
    class ResultSet;
}

class QueryCallback {
public:
    QueryCallback(std::future<std::unique_ptr<sql::ResultSet>> &&future, std::function<void(std::unique_ptr<sql::ResultSet>)> &&cb)
        : future_(std::move(future)), cb_(std::move(cb))
    {
    }

    bool InvokeIfReady() {
        if (future_.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
            cb_(std::move(future_.get()));
            return true;
        }
        return false;
    }
private:
    std::future<std::unique_ptr<sql::ResultSet>> future_;
    std::function<void(std::unique_ptr<sql::ResultSet>)> cb_;
};

//AsyncProcessor.h

class QueryCallback;
class AsyncProcessor
{
public:
    void AddQueryCallback(QueryCallback &&query_callback);
    void InvokeIfReady();

private:
    std::vector<QueryCallback> pending_queries_;
};

 

...全文
37 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

440

社区成员

发帖
与我相关
我的任务
社区描述
零声学院,目前拥有上千名C/C++开发者,我们致力将我们的学员组织起来,打造一个开发者学习交流技术的社区圈子。
nginx中间件后端 企业社区
社区管理员
  • Linux技术狂
  • Yttsam
  • 零声教育-晚晚
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

请新加入的VIP学员,先将自己参加活动的【所有文章】,同步至社区:

【内容管理】-【同步至社区-【零声开发者社区】

试试用AI创作助手写篇文章吧