个人主页艾莉丝努力练剑❄专栏传送门《C语言》《数据结构与算法》《C/C干货分享学习过程记录》《Linux操作系统编程详解》《笔试/面试常见算法从基础到进阶》《Python干货分享》⭐️为天地立心为生民立命为往圣继绝学为万世开太平 艾莉丝的简介文章目录1 ~ MySQL 连接池原理与实现1.1 连接池产生背景短连接的性能瓶颈1.2 连接池核心设计思想1.3 线程绑定式连接池实现模型1.3.1 核心组件1.3.2 任务执行与回调机制1.3.3 连接保活与故障恢复1.3.4 单连接基础 API 示例1.4 完整 C MySQL 连接池工程实现1.4.1 核心设计约束1.4.2 完整可运行代码1.5 业界主流连接池组件2 ~ 网站数据流动与分布式架构演进2.1 基础 Web 业务全链路注册 / 登录场景2.1.1 用户注册全链路2.1.2 用户登录全链路2.2 数据库层架构演进2.2.1 单库架构2.2.2 主从复制与读写分离2.2.3 数据库中间件与负载均衡2.3 缓存层设计2.4 大规模分布式架构核心组件结尾1 ~ MySQL 连接池原理与实现1.1 连接池产生背景短连接的性能瓶颈传统数据库短连接模式下每次执行 SQL 都会执行完整的生命周期创建 MySQL 句柄对象发起 TCP 连接、完成 MySQL 身份认证执行 SQL 语句、处理结果关闭连接、释放资源核心弊端频繁的 TCP 三次握手、四次挥手带来巨大网络开销MySQL 连接的身份认证、权限校验属于重操作重复执行严重浪费 CPU 资源高并发场景下大量连接的创建与销毁会导致数据库连接数溢出引发服务雪崩1.2 连接池核心设计思想核心本质空间换时间预先创建一批数据库连接并长期保持活跃业务请求直接复用已有连接避免重复建连开销。核心价值消除连接建立与销毁的开销大幅降低 SQL 执行延迟统一管控连接数量避免数据库连接数超出上限统一封装数据库操作业务层无需关心连接底层细节1.3 线程绑定式连接池实现模型该模型是 C/C 生态最常用的连接池实现方案核心逻辑为一个工作线程绑定一个数据库连接基于线程池实现任务调度。1.3.1 核心组件任务队列全局共享的阻塞队列存储待执行的 SQL 任务任务结构体包含两个核心字段SQL 语句、回调函数对象多线程环境下通过互斥锁保证队列操作线程安全通过条件变量实现任务等待与唤醒工作线程池预先创建的 N 个工作线程每个线程启动阶段就完成 MySQL 连接建立线程生命周期内持有该连接句柄线程进入事件主循环阻塞等待任务队列取出任务后通过自身持有的连接执行 SQL连接句柄每个线程独立持有一个MYSQL*对象全程绑定不跨线程传递。关键约束MySQL 连接句柄不是线程安全的绝对禁止多线程共享同一个连接句柄并发执行 SQL这也是 “一线程一连接” 设计的核心依据。1.3.2 任务执行与回调机制任务提交业务层将 SQL 语句与回调函数封装为任务对象推入任务队列任务执行工作线程取出任务调用mysql_query接口执行 SQL 语句结果回调增删改类 SQL若无回调则直接结束有回调则将执行状态码传入回调函数查询类 SQL执行后通过mysql_store_result获取结果集将结果集传入回调函数由业务层处理数据设计意义实现异步数据库操作业务层提交任务后无需阻塞等待结果通过回调函数异步返回。1.3.3 连接保活与故障恢复问题MySQL 连接可能因网络波动、服务端超时等原因断开直接执行 SQL 会报错标准解决方案执行 SQL 前调用mysql_ping()检测连接有效性若连接已断开调用mysql_real_connect重新建立连接也可通过mysql_options设置MYSQL_OPT_RECONNECT选项开启客户端自动重连能力1.3.4 单连接基础 API 示例以下为 C 调用 MySQL C API 的基础连接实现是连接池单线程的核心逻辑原型#includeiostream#includestring#includemysql/mysql.h// 数据库连接配置conststd::string hostlocalhost;// 修正原笔记拼写错误conststd::string userconnector;conststd::string passwd123456;conststd::string dbconn;constunsignedintport3306;// 修正原笔记端口错误MySQL默认端口3306intmain(){// 1. 初始化MySQL句柄MYSQL*mymysql_init(nullptr);if(nullptrmy){std::cerrinit MySQL errorstd::endl;return1;}// 2. 建立数据库连接线程启动阶段执行一次if(mysql_real_connect(my,host.c_str(),user.c_str(),passwd.c_str(),db.c_str(),port,nullptr,0)nullptr){std::cerrconnect MySQL error: mysql_error(my)std::endl;return2;}// 3. 设置连接字符集mysql_set_character_set(my,utf8);// 4. 执行SQL语句事件循环中每次取出任务后执行// 增删改操作示例// std::string sql insert into user (name, age, telephone) values(张, 19, 6543219);// std::string sql update user set nameJimmy where id2;// std::string sql delete from user where id5;// 查询操作示例std::string sqlselect * from user;intretmysql_query(my,sql.c_str());if(ret0){std::coutsql execute successstd::endl;// 查询类SQL需要获取结果集回调函数通常在此处触发MYSQL_RES*resmysql_store_result(my);if(res){MYSQL_ROW row;// 遍历结果集将数据传入回调函数while((rowmysql_fetch_row(res))!nullptr){std::coutid: row[0], name: row[1]std::endl;}mysql_free_result(res);}}else{std::cerrsql execute failed: mysql_error(my)std::endl;return3;}// 连接池场景下连接不关闭线程生命周期结束时再释放mysql_close(my);return0;}1.4 完整 C MySQL 连接池工程实现1.4.1 核心设计约束线程与连接一一绑定连接生命周期与线程生命周期完全一致符合 MySQL 连接非线程安全的底层约束基于生产者 - 消费者模型通过互斥锁 条件变量实现任务队列的线程安全调度内置连接保活机制自动检测连接状态并完成重连提升服务可用性基于std::function实现通用回调接口支持任意业务层的结果处理逻辑RAII 资源管理析构时自动停止线程、释放所有数据库连接无内存与连接泄漏1.4.2 完整可运行代码#includeiostream#includestring#includevector#includequeue#includethread#includemutex#includecondition_variable#includefunctional#includeatomic#includechrono#includemysql/mysql.h// 数据库任务结构体封装SQL语句与结果回调structSqlTask{std::string sql;// 回调函数签名参数1为执行结果码0成功非0失败参数2为查询结果集仅查询类SQL有效std::functionvoid(int,MYSQL_RES*)callback;};// MySQL连接池类线程绑定式实现classMysqlConnectionPool{public:/** * brief 构造函数 * param pool_size 连接池大小工作线程数 数据库连接数 * param host 数据库主机地址 * param user 数据库用户名 * param passwd 数据库密码 * param db 目标数据库名 * param port 数据库端口 */MysqlConnectionPool(size_t pool_size,conststd::stringhost,conststd::stringuser,conststd::stringpasswd,conststd::stringdb,unsignedintport);// 析构函数停止线程池释放所有数据库连接~MysqlConnectionPool();// 禁止拷贝构造与赋值资源类禁止拷贝MysqlConnectionPool(constMysqlConnectionPool)delete;MysqlConnectionPooloperator(constMysqlConnectionPool)delete;/** * brief 向连接池提交SQL任务生产者接口 * param task 待执行的SQL任务 */voidpushTask(constSqlTasktask);private:/** * brief 工作线程入口函数消费者逻辑 * 每个线程独立创建并持有一个MySQL连接全程绑定 */voidworkerThread(conststd::stringhost,conststd::stringuser,conststd::stringpasswd,conststd::stringdb,unsignedintport);/** * brief 连接保活检测与自动重连 * param mysql 待检测的MySQL连接句柄 * return true 连接可用false 连接失效且重连失败 */boolensureConnected(MYSQL*mysql);private:std::vectorstd::threadm_workers;// 工作线程池std::queueSqlTaskm_taskQueue;// 全局任务队列std::mutex m_queueMutex;// 任务队列互斥锁std::condition_variable m_cond;// 任务唤醒条件变量std::atomicboolm_isStop;// 线程池停止标志原子变量保证线程可见};// 类成员函数实现 MysqlConnectionPool::MysqlConnectionPool(size_t pool_size,conststd::stringhost,conststd::stringuser,conststd::stringpasswd,conststd::stringdb,unsignedintport):m_isStop(false){// 批量创建工作线程每个线程独立完成MySQL连接初始化for(size_t i0;ipool_size;i){m_workers.emplace_back(MysqlConnectionPool::workerThread,this,host,user,passwd,db,port);}}MysqlConnectionPool::~MysqlConnectionPool(){// 1. 设置停止标志通知所有线程退出循环m_isStop.store(true);// 2. 唤醒所有阻塞在条件变量上的线程m_cond.notify_all();// 3. 等待所有线程安全退出回收资源for(autoth:m_workers){if(th.joinable()){th.join();}}}voidMysqlConnectionPool::pushTask(constSqlTasktask){{std::lock_guardstd::mutexlock(m_queueMutex);m_taskQueue.push(task);}// 任务入队后唤醒一个工作线程处理m_cond.notify_one();}boolMysqlConnectionPool::ensureConnected(MYSQL*mysql){if(mysqlnullptr){returnfalse;}// mysql_ping返回0表示连接存活非0表示连接已断开if(mysql_ping(mysql)!0){std::cerr[Warning] MySQL connection lost, try reconnect...std::endl;// 连接断开执行重连if(mysql_real_connect(mysql,nullptr,nullptr,nullptr,nullptr,0,nullptr,0)nullptr){std::cerr[Error] MySQL reconnect failed: mysql_error(mysql)std::endl;returnfalse;}// 重连后重置字符集mysql_set_character_set(mysql,utf8);}returntrue;}voidMysqlConnectionPool::workerThread(conststd::stringhost,conststd::stringuser,conststd::stringpasswd,conststd::stringdb,unsignedintport){// 线程初始化阶段创建并建立数据库连接 MYSQL*mysqlmysql_init(nullptr);if(mysqlnullptr){std::cerr[Error] mysql_init failed in worker threadstd::endl;return;}if(mysql_real_connect(mysql,host.c_str(),user.c_str(),passwd.c_str(),db.c_str(),port,nullptr,0)nullptr){std::cerr[Error] worker thread connect MySQL failed: mysql_error(mysql)std::endl;mysql_close(mysql);return;}mysql_set_character_set(mysql,utf8);// 线程主循环阻塞取任务 - 执行SQL - 回调通知 while(!m_isStop.load()){SqlTask task;{std::unique_lockstd::mutexlock(m_queueMutex);// 条件变量等待谓词判断防止虚假唤醒m_cond.wait(lock,[this](){return!m_taskQueue.empty()||m_isStop.load();});// 停止标志触发且无剩余任务时退出主循环if(m_isStop.load()m_taskQueue.empty()){break;}// 取出队首任务taskstd::move(m_taskQueue.front());m_taskQueue.pop();}// 执行SQL前先做连接保活检测if(!ensureConnected(mysql)){// 连接不可用通过回调通知业务层错误if(task.callback){task.callback(-1,nullptr);}continue;}// 执行SQL语句intretmysql_query(mysql,task.sql.c_str());if(ret!0){std::cerr[Error] sql execute failed: task.sql, reason: mysql_error(mysql)std::endl;if(task.callback){task.callback(ret,nullptr);}continue;}// SQL执行成功获取结果集MYSQL_RES*resmysql_store_result(mysql);// 执行回调将结果交付给业务层if(task.callback){task.callback(0,res);}// 释放结果集资源必须释放否则造成内存泄漏if(res){mysql_free_result(res);}}// 线程退出阶段关闭数据库连接 mysql_close(mysql);}// 使用示例 intmain(){// 1. 初始化连接池设置4个连接4个工作线程MysqlConnectionPoolpool(4,localhost,connector,123456,conn,3306);// 2. 提交写入任务无回调异步执行SqlTask insert_task;insert_task.sqlinsert into user (name, age, telephone) values(pool_test, 22, 987654321);pool.pushTask(insert_task);// 3. 提交查询任务带回调异步接收结果SqlTask select_task;select_task.sqlselect id, name, age from user;select_task.callback[](intret,MYSQL_RES*res){if(ret!0||resnullptr){std::coutquery execute failedstd::endl;return;}// 业务层遍历处理结果集MYSQL_ROW row;std::cout query result std::endl;while((rowmysql_fetch_row(res))!nullptr){std::coutid: row[0], name: row[1], age: row[2]std::endl;}};pool.pushTask(select_task);// 演示等待实际工程中无需此操作此处保证任务执行完成std::this_thread::sleep_for(std::chrono::seconds(2));return0;}1.5 业界主流连接池组件Java 生态HikariCP目前性能最优的 JDBC 连接池、Druid带监控与防火墙能力、C3P0C/C 生态多为业务自研实现也可基于 MySQL Connector/C、libzdb 等开源库二次封装2 ~ 网站数据流动与分布式架构演进2.1 基础 Web 业务全链路注册 / 登录场景2.1.1 用户注册全链路客户端发起 HTTP 请求访问网站注册页面Web 服务器Nginx/Tomcat接收请求返回前端注册页面用户填写用户名、密码、手机号等信息通过 POST 方法提交表单数据后端服务PHP/Python/Java/C提取表单参数完成合法性校验后端构建 INSERT SQL 语句调用数据库连接池执行写入操作用户数据持久化到 MySQL 用户表注册流程完成2.1.2 用户登录全链路客户端发起 HTTP 请求访问网站登录页面Web 服务器返回登录页面用户输入用户名、密码通过 POST 方法提交禁止 GET 提交密码防止明文泄露后端提取参数构建 SELECT 查询 SQL查询条件为用户名 密码连接池执行 SQL从数据库查询匹配记录若查询到记录说明用户身份合法后端生成 Cookie/Session 信息返回客户端登录成功若无匹配记录返回账号或密码错误提示2.2 数据库层架构演进2.2.1 单库架构小型网站初期形态所有读写操作都访问同一台 MySQL 服务器弊端存在单点故障风险、性能上限低无法支撑高并发读写场景2.2.2 主从复制与读写分离核心架构一主多从主库Master负责所有写操作从库Slave负责读操作数据同步主库通过 binlog 日志将数据变更同步到所有从库保证数据最终一致性核心优势读写分流大幅提升数据库并发处理能力从库可做冷备降低数据丢失风险2.2.3 数据库中间件与负载均衡引入原因业务层直接对接多台数据库会导致耦合度高无法统一管控中间件核心作用对业务层屏蔽后端数据库集群细节业务层只需对接中间件实现 SQL 路由、读写分离、读请求负载均衡统一管控连接数、权限控制、SQL 监控与审计常见中间件ShardingSphere、MyCat、ProxySQL2.3 缓存层设计引入背景高频热点数据每次都查询数据库会给数据库造成巨大压力核心思想查询请求优先访问缓存缓存命中直接返回缓存未命中再查询数据库同时将数据回写缓存主流缓存组件Redis分布式缓存首选、Memcached2.4 大规模分布式架构核心组件随着业务规模扩大架构会逐步引入更多分布式组件容器化与编排Docker应用容器化、KubernetesK8S容器集群编排消息队列Kafka、RabbitMQ用于异步解耦、流量削峰分布式存储应对海量数据存储需求微服务治理服务注册发现、熔断降级、全链路追踪技术栈定位补充Java建站效率高、生态完善是互联网业务后端的主流选择C/C性能优势明显常用于高性能中间件、底层基础组件开发PHP/Python适合小型项目、快速迭代的业务场景结尾uu们本文的内容到这里就全部结束了艾莉丝在这里再次感谢您的阅读艾莉丝努力练剑C/C Linux 底层探索者 | 一个正在努力练剑的技术博主【关注】跟随我一起深耕技术领域见证每一次成长。❤️【点赞】让优质内容被更多人看见让知识传递更有力量。⭐【收藏】把核心知识点存好在需要时随时查、随时用。【评论】分享你的经验或疑问评论区一起交流避坑不要忘记给博主“一键四连”哦“今日练剑达成”“技术之路难免有困惑但同行的人会让前进更有方向。”结语希望对学习Linux相关内容的uu有所帮助不要忘记给博主“一键四连”哦往期回顾【MYSQL】MYSQL学习的一大重点三种方案访问MYSQL博主在这里放了一只小狗大家看完了摸摸小狗放松一下吧૮₍ ˶ ˊ ᴥ ˋ˶₎ა