Druid之连接池

article/2025/9/15 13:23:16

需要注意的是,我们下面提供的几种实现方式都是基于简单的原型,目的是带你了解连接池实现的一些基本原理。真实的数据库连接池技术需要考虑更多复杂的细节。

所以下面这些代码都是不能在生产上直接使用的

实现的时候会用到java.sql.Connection,由于这个只是一个接口无法创建实例,为了演示方便,我继承这个接口写了一个简单的测试类,只是在commit方法里加了延时模拟提交。

实现方式1:

很容易马上想到的一种方案,我们用一个map存放连接对象,需要的时候从map里拿来用就可以了。

这里需要注意,尽管我们使用了线程安全的ConcurrentHashMap来存放连接资源,getConnection方法依然要加上synchronized关键字来避免并发问题。这一点是最容易忽略的。

试想一下,假设在某个场景下,我们希望某个应用的多个线程共享连接资源。

假设有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等,方面进行统一管理


http://chatgpt.dhexx.cn/article/2td4lfVS.shtml

相关文章

Druid连接池核心原理

一、什么是Druid连接池? Druid连接池是阿里巴巴开源的数据库连接池项目。Druid连接池为监控而生,内置强大的监控功能,监控特性不影响性能。功能强大,能防SQL注入,内置Loging能诊断Hack应用行为。 竞品对比 从上表可以…

德鲁伊连接池(druid)

文章目录 一、连接池1、什么是连接池2、为什么要用连接池 二、德鲁伊连接池(druid)1.介绍2.代码实操 一、连接池 1、什么是连接池 简单来说就是一组连接组成的一个池子(集合),称为连接池。 连接池是创建和管理一个连接的缓冲池技术。 2、为什么要用连…

【Druid 连接池】 学习~快速 掌握连接池基本原理

文章目录 前言提出问题:一、Druid连接池简述 再次提出问题 :二、初始化连接池三、了解三个核心成员(三大线程)四、获取连接五、探活(连接池连接健康的检查机制) 前言 翻遍了各个大佬发的博客整理出来的学习…

Druid连接池的基本配置与使用

Druid简介 Druid是阿里巴巴的开源连接池组件,是世界上最好的连接池之一。Druid能对数据库连接进行有效管理和重用,最大化程序执行的效率。连接池负责创建和管理连接,程序只负责取用与归还。 以下是我画的示意图: 下面我来给大家…

MySQL快捷键注释

MySQL语句注释快捷键显示为CtrlOemQuestion,对应于我们键盘上的是Ctrl?

Mysql 增加表注释

关注微信公共号:小程在线 关注CSDN博客:程志伟的博客 方法一: mysql添加表注释 ALTER TABLE 表名 COMMENT 注释字段; 实例: alter table test comment 测试表; 方法二: 在创建表的时候直接增加表注释…

mysql语句中的注释方法_MySQL语句注释方式简介

MySQL支持三种注释方式: 1.从‘#字符从行尾。 2.从‘-- 序列到行尾。请注意‘-- (双破折号)注释风格要求第2个破折号后面至少跟一个空格符(例如空格、tab、换行符等等)。 3.从/*序列到后面的*/序列。结束序列不一定在同一行中,因此该语法允许注释跨越多行…

MySQL注释:单行注释和多行注释,快进来理解

单行注释与多行注释 单行注释多行注释 单行注释 单行注释可以使用#注释符,#注释符后直接加注释内容 #注释内容单行注释可以使用- -注释符,- -注释符后需要加一个空格,注释才能生效。 -- 注释内容#和–的区别就是:#后面直接加注…

Mysql注释

Mysql注释 MySQL服务器支持3种注释风格: 从‘#’字符从行尾。 从‘-- ’序列到行尾。请注意‘-- ’(双破折号)注释风格要求第2个破折号后面至少跟一个空格符(例如空格、tab、换行符等等)。该语法与标准SQL注释语法稍有不同。 从/*序…

mysql注释乱码问题_mysql注释是中文乱码怎么办

mysql注释是中文乱码的解决办法:首先用“show variables like”命令查看数据库与服务端的字符集设置;然后执行语句为“set collation_serverutf8_general_ci;”即可。 mysql表注释乱码 问题 执行语句: alter table TABLE_XXX comment ‘中文号’; 结果: …

wepy开发小程序eslint报错error 'getApp' is not defined no-undef

wepy开发小程序使用getApp().globalData保存全局数据很方便,但是会在控制台看到很多报错:“error getApp is not defined no-undef”,这是eslint报错。 解决办法:在.eslintrc.js文件中加入 globals: { getApp: true } 转载于:ht…

微信小程序 关于获取用户信息的一种方法 “this.setData与getApp().globalData.userInfo“

获取用户信息&#xff1a;this.setData和getApp().globalData.userInfo; 最开始的WXML文件中&#xff0c;我们写下页面结构代码如下&#xff1a; <image class"userinfo-avatar" src"{{userInfo.avatarUrl}}" mode"cover"></image>…

JS交互逻辑——获取页面数据{{}}和全局数据const app = getApp()

JS交互逻辑 在小程序里边&#xff0c;我们就通过编写 JS 脚本文件来处理用户的操作 app.js中最外层需要App({}) &#xff0c;该函数是微信平台提供的api App({// 全局数据&#xff0c;可以在所有的子页面中使用mydata: {n: 100} }) // 页面获取全局数据的方式,app表示小程序的…

微信小程序getApp().globalData.user无法获取值

一、debug过程 在进行微信小程序的开发过程中&#xff0c;我利用如下代码获取全局变量中的username的值&#xff0c;但其结果缺如图中所示的只向数据库中存入了对应的类型即object Object。 username: getApp().globalData.user.username, 数据库结果 其中&#xff0c;全局变量…

微信小程序const app=getApp()的作用,实现page页面获取全局数据

app.js的作用 app.js是整个小程序项目的入口文件&#xff0c; 如果小程序要运行&#xff0c;第一个被执行的文件就是app.js&#xff0c;第一个被执行的代码是app.js中的onLaunch方法 在app.js中可以书写小程序的全局业务逻辑 在app.js里面&#xff0c;写上一些需要的东西&am…

uniapp中的getApp().globalDate.

获取全局变量&#xff1a; getApp().globalDate1.uni-app 在app.vue文件export default里面定义globalData&#xff0c;在其他文件则用getApp&#xff08;&#xff09;.globalData获取 2.在当前文件&#xff08;app.vue&#xff09;里面获取globalData需要用this.$options.glob…

解释微信小程序const app=getApp()的作用

const appgetApp()用来获取全局变量 const appgetApp()这就话通常在pages下的页面的js中写 来调用app.js中的globalData{} 直白一点说就是在app.js的globalData{}里写的东西 在其他页面的js的onshow中可以直接调用 例&#xff1a;

微信小程序 app=getApp()公共变量在页面间传值技巧。

1.公共变量 在开发过程中&#xff0c;避免不了会使用公共变量&#xff0c;记录共享对象状态、数据最简单的方式就是创建创建公共变量&#xff1b; 当业务逻辑变多&#xff0c;还采用这种思想就会变得危险&#xff0c;代码逻辑变得不清晰&#xff0c;慢慢就有一种代码坏味道。 …

【uniapp】uniapp的globalData以及getApp():

文章目录 一、说明文档&#xff1a;二、使用&#xff1a; 一、说明文档&#xff1a; 【官方文档】https://uniapp.dcloud.net.cn/collocation/App.html#globaldata 二、使用&#xff1a;

getapp.php,getApp.php

下载RiseClub $iosUrl https://itunes.apple.com/cn/app/riseclub/id869364498?lzh&mt8; $yingyongbao http://a.app.qq.com/o/simple.jsp?pkgnamecom.rusi.club&g_f994302; $androidUrl http://club.risecenter.com/riseclub.v1.1.2.apk; if(isset($_GET[go2Andr…