数据库连接池的原理没你想得这么繁杂

小微 科技数据库连接池的原理没你想得这么繁杂已关闭评论101字数 1972阅读模式
摘要封图| CSDN 下载于视觉中国背景介绍数据库连接池和线程池等池技术存在的意义都是为了解决资源的重复利用问题。在计算机里,创建一个新的资源往往开销是非常大的。而池技术可以统一分配,...

背景介绍

数据库连接池以及线程池等池技术存在的意义都是为了解决资源的重复应用问题。在计算机里,创立一个新的资源常常开消是无比大的。而池技术可以统一分配,管理某一类资源,它允许咱们的程序可以重复的使用这个资源,只有在极端情况下(比如连接池满)才会创立新的资源。文章源自微观生活(93wg.com)微观生活-https://93wg.com/24456.html

数据库连接这类资源特别昂贵,它的创立开消很大,大量的创立连接以及释放操作对程序的影响无比显明。文章源自微观生活(93wg.com)微观生活-https://93wg.com/24456.html

数据库连接池恰是针对这个问题提出来的。文章源自微观生活(93wg.com)微观生活-https://93wg.com/24456.html

实现原理文章源自微观生活(93wg.com)微观生活-https://93wg.com/24456.html

需要注意的是,咱们下面提供的几种实现方式都是基于简单的原型,目的是带你了解连接池实现的一些基本原理。真正的数据库连接池技术需要斟酌更多繁杂的细节。文章源自微观生活(93wg.com)微观生活-https://93wg.com/24456.html

所下列面这些代码都是不能在生产上直接使用的。文章源自微观生活(93wg.com)微观生活-https://93wg.com/24456.html

实现的时候会用到java.sql.Connection,因为这个只是一个接口没法创立实例,为了演示利便,我继承这个接口写了一个简单的测试类,只是在co妹妹it办法里加了延时摹拟提交。文章源自微观生活(93wg.com)微观生活-https://93wg.com/24456.html

实现方式1:文章源自微观生活(93wg.com)微观生活-https://93wg.com/24456.html

很容易马上想到的一种方案,咱们用一个map寄存连接对象,需要的时候从map里拿来用就能够了。文章源自微观生活(93wg.com)微观生活-https://93wg.com/24456.html

这里需要注意,虽然咱们使用了线程安全的ConcurrentHashMap来寄存连接资源,getConnection办法仍然要加之synchronized关键字来防止并提问题。这一点是最容易疏忽的。文章源自微观生活(93wg.com)微观生活-https://93wg.com/24456.html

试想一下,假定在某个场景下,咱们但愿某个利用的多个线程同享连接资源。

假定有2个线程同时执行到了pool.containsKey(key),然后都返回false,那这两个线程都会创立连接。尽管ConcurrentHashMap的put办法只会加入其中一个,但还是生成为了1个过剩的连接。

缘由在于,虽然ConcurrentHashMap自身每一个操作都是线程安全的,然而当这些操作组合在一块儿使用的时候,就没法保证原子性了,所以有可能带来并发的问题。

这里友谊提醒下,面试时常会遇到这个考点哦。

实现方式 2:

第二种实现方式是在1的基础上进行的优化。1的方案有个问题就是每一次走访getConnection都要加锁,释放锁,效力比较低。

第二种方案是应用java并发包里的Future机制来解决并发场景创立过剩连接的问题。

咱们来捋一捋这个实现会不会有并发的问题。假定两个线程同时进入else分支,在代码的28行ConcurrentHashMap可以确保只有一个线程会执行,也就是只会加入一个task。其它的线程都不会加入胜利。

所以只有一个线程connectionFutureTask == null,这个线程开始异步执行创立连接的任务,而其它的线程则会调用FutureTask的get办法直接获取结果。

实现方式3:

1以及2的实现方式还存在一个问题, 多个线程获取到的其实同一个连接。这类方案在某些场景下是不允许的。比如spring数据库的事务管理器对于每一个事务的处理线程都请求独立的连接资源。

下面的方案基于链表结构,有比较完全的获取,释放的操作,不同的线程可以拿到独立的连接资源。

注意到这个方案咱们在获取连接的时候引入了超时时间,如果该办法能够在一段时间内获取到结果,那么将结果立刻返回,反之,超时返回默许结果。

druid连接池的实现原理

了解了实现连接池的大概思路,咱们可以来继续学习下市面上比较成熟的连接池产品。这其中阿里巴巴开源的druid开源连接池就是一个代表。

Druid作为java领域最佳的连接池技术之一,连接池自身只是它的一部份功能。除了此以外,它还还要配套的监控功能。固然这个不是咱们

先来看看在代码中怎么使用Druid连接池,

所以继续深刻到是DataSource里的getConnection办法,

init办法主要的功能是依据配置文件初始化连接池,它内部会生成一些真实的物理连接然后放入一个数组里。固然这个办法要保证只会被调用一次。

继续往下看,终究会调用到getConnectionInternal这个私有办法,

红色圈出的部份是核心,依据传入的等待时间走不同的分支,咱们来看看takeLast办法。

代码逻辑也比较清楚,poolCount是连接池的目前的可用连接数量。

如果为0,就通过emptySignal唤醒生产者线程创立新的连接,同时当前线程挂起等待notEmpty的信号。notEmptyWaitCount保护的就是正在等待的消费者数量。

如果不为0,就从数组中掏出最后一个连接返回。有人可能会有疑难,这里返回的是DruidConnectionHolder,不是Connection啊?

其实看下前者的定义你就明白了,

DruidConnectionHolder封装了Connection和连接的datasource信息,还有多个statement等,方面进行统一管理。

以上就是微观生活(93wg.com)关于“数据库连接池的原理没你想得这么繁杂”的详细内容,希望对大家有所帮助!

继续阅读
 
小微
  • 版权声明: 本文部分文字与图片资源来自于网络,转载此文是出于传递更多信息之目的,若有来源标注错误或侵犯了您的合法权益,请立即通知我们(管理员邮箱:81118366@qq.com),情况属实,我们会第一时间予以删除,并同时向您表示歉意,谢谢!
  • 转载请务必保留本文链接:https://93wg.com/24456.html