C++实现的小型项目, MySQL数据库连接池, 属于常用组件;
约400到500行代码, 代码不多, 麻雀虽小, 五脏俱全:
- 涉及到数据库编程;
- 单例模式
- queue队列容器
C++11
多线程编程, 线程互斥, 线程同步通信,unique_lock
- 基于CAS的原子类型
- 智能指针
shared_ptr
- lambda表达式
- 生产者-消费者线程模型
为了提高MySQL数据库(需要特别注意的, 它是基于C/S设计的)的访问瓶颈,除了在服务器端增加缓存服务器缓存常用的数据之外(例如Redis),还可以增加连接池,来提高MySQL Server的访问效率,在高并发情况下,大量的TCP三次握手、MySQL Server连接认证、MySQL Server关闭连接回收资源和TCP四次挥手所耗费的性能时间也是很明显的,增加连接池就是为了减少这一部分的性能损耗。
在市场上比较流行的连接池包括阿里的druid,c3p0以及apache dbcp连接池,它们对于短时间内大量的数据库增删改查操作性能的提升是很明显的,但是它们全部由Java实现。那么本项目就是为了在C/C++
语言下,提供MySQL Server的访问效率,实现基于C++
代码的数据库连接池模块。
该项目是基于C++语言实现的连接池,主要实现若干个通用基础功能。
连接池一般包含了数据库连接所用的ip地址、port端口号、用户名和密码以及其它的性能参数,例如初 始连接量,最大连接量,最大空闲时间、连接超时时间等;
- 初始连接量(initSize)
- 表示连接池事先会和MySQL Server创建initSize个数的connection连接;
- 当应用发起MySQL访问时,不用再创建和MySQL Server新的连接,直接从连接池中获取一个可用的连接就可以;
- 使用完成后,并不去释放connection,而是把当前connection再归还到连接池当中。
- 最大连接量(maxSize)
- 总的连接数量上限是maxSize;
- 当并发访问MySQL Server的请求增多时,初始连接量已经不够使用了,此时会根据新的请求数量去创建更多的连接给应用去使用;
- 但是,不能无限制的创建连接,因为每一个连接都会占用一个socket资源,一般连接池和服务器程序是部署在一台主机上的,如果连接池占用过多的socket资源,那么服务器就不能接收太多的客户端请求了;
- 当这些连接使用完成后,再次归还到连接池当中来维护。
- 最大空闲时间(maxIdleTime)
- 当访问MySQL的并发请求多了以后,连接池里面的连接数量会动态增加,上限是maxSize个;
- 当这些连接用完再次归还到连接池当中;
- 如果在指定的maxIdleTime里面,这些新增加的连接都没有被再次使用过,那么新增加的这些连接资源就要被回收掉,只需要保持初始连接量initSize个连接就可以了。
- 连接超时时间(connectionTimeout)
- 当MySQL的并发请求量过大,连接池中的连接数量已经到达maxSize了,而此时没有空闲的连接可供使用,那么此时应用从连接池获取连接需要通过阻塞的方式获取连接;
- 阻塞时间如果超过connectionTimeout时间,那么获取连接失败,无法访问数据库;
该项目主要实现上述的连接池四大功能,其余连接池更多的扩展功能,可以在该框架的基础上进行很好的拓展;
- 需要抽象出两个类
- ConnectionPool - 连接池
- Connection - 封装数据库操作, 增删改查
- 连接池只需要一个实例, 则ConnectionPool设计为单例模式
- ConnectionPool需要提供获取MySQL连接Connection的接口
- 空闲连接Connection全部维护在一个Connection队列中, 使用互斥锁保证队列的线程安全
- 如果在获取连接时发现空闲连接队列空, 则需要动态创建新连接, 但是上限数量是maxSize, 在创建新连接的过程中, 消费者线程需要忙等待connectionTimeout时长, 直到队列中不空; 若时长一到仍获取未果则认定为连接失败; 可以使用带超时时间的mutex互斥锁来实现连接超时时间;
- 使用量下降后, 如果队列中的空闲连接保持空闲超过maxIdleTime, 需要释放连接, 直到减少到initSize个连接; 这个释放的过程需要放在独立线程做 - 定时线程, 清理队列多余的空闲连接;
- 用户获取的连接用
shared_ptr
智能指针来管理,用lambda表达式定制连接释放的功能(不真正释放连接,而是把连接归还到连接池中) - 连接的生产和连接的消费采用
生产者-消费者
线程模型来设计,使用了线程间的同步通信机制条件变量和互斥锁;