2022-05-12 Druid源码阅读——poolPreparedStatements是如何控制缓存游标的?
在Druid预编译SQL时,会检查是否开启poolPreparedStatements参数缓存预编译SQL,这些预编译的SQL存放在哪里?在什么时候进行存放?
1.如何开启poolPreparedStatements(PSCache)功能
需要注意的是,maxPoolPreparedStatementPerConnectionSize的加载顺序在poolPreparedStatements之后,如果将maxPoolPreparedStatementPerConnectionSize设置为负数,则poolPreparedStatements无法生效。
- 将
druid.poolPreparedStatements
配置项设置为true,此时maxPoolPreparedStatementPerConnectionSize默认为10。 - 将
druid.maxPoolPreparedStatementPerConnectionSize
参数值设置为>0的整数,也会开启此功能
2.预编译的SQL缓存在哪里?
通过分析预编译SQL部分,可以发现这些内容被存放在连接持有者的statementPool属性中。
public final class DruidConnectionHolder {protected PreparedStatementPool statementPool;/*** 获得语句池*/public PreparedStatementPool getStatementPool() {//如果语句池为空,则新建语句池,否则返回当前所持有的if (statementPool == null) {statementPool = new PreparedStatementPool(this);}return statementPool;}
}
也就是说,预编译的SQL,会被存放在当前连接的持有者中,这些预编译的内容不会被其他连接所共享。
3.预编译的SQL是什么时候被添加进缓存的?
由于预编译SQL时,没有将语句缓存到语句池中,推测是在语句关闭时进行处理。
@Overridepublic void close() throws SQLException {//如果当前语句已经被关闭(内部状态判断),则不进行处理if (isClosed()) {return;}//判断当前连接是否被关闭(同样通过内部状态进行判断,此时如果为true,该连接处于等待回收或正在回收)boolean connectionClosed = this.conn.isClosed();// Reset the defaults//如果当前开启了PSCache,并且连接没有被关闭,重置数值到默认if (pooled && !connectionClosed) {try {if (defaultMaxFieldSize != currentMaxFieldSize) {stmt.setMaxFieldSize(defaultMaxFieldSize);currentMaxFieldSize = defaultMaxFieldSize;}if (defaultMaxRows != currentMaxRows) {stmt.setMaxRows(defaultMaxRows);currentMaxRows = defaultMaxRows;}if (defaultQueryTimeout != currentQueryTimeout) {stmt.setQueryTimeout(defaultQueryTimeout);currentQueryTimeout = defaultQueryTimeout;}if (defaultFetchDirection != currentFetchDirection) {stmt.setFetchDirection(defaultFetchDirection);currentFetchDirection = defaultFetchDirection;}if (defaultFetchSize != currentFetchSize) {stmt.setFetchSize(defaultFetchSize);currentFetchSize = defaultFetchSize;}} catch (Exception e) {this.conn.handleException(e, null);}}//由连接对象对预编译语句进行处理conn.closePoolableStatement(this);}
/*** 关闭预编译语句*/
public void closePoolableStatement(DruidPooledPreparedStatement stmt) throws SQLException {//获得原始的预编译语句对象PreparedStatement rawStatement = stmt.getRawPreparedStatement();//获得当前连接的持有者final DruidConnectionHolder holder = this.holder;//如果当前连接不再被持有,则不处理if (holder == null) {return;}//判断是否开启了缓存预编译语句if (stmt.isPooled()) {try {//清空预编译语句中所有的参数rawStatement.clearParameters();} catch (SQLException ex) {//处理异常this.handleException(ex, null);//判断当前连接是否被放弃,如果放弃不继续处理if (rawStatement.getConnection().isClosed()) {return;}LOG.error("clear parameter error", ex);}try {//清除所有的批处理rawStatement.clearBatch();} catch (SQLException ex) {this.handleException(ex, null);if (rawStatement.getConnection().isClosed()) {return;}LOG.error("clear batch error", ex);}}//获得当前语句的持有者PreparedStatementHolder stmtHolder = stmt.getPreparedStatementHolder();//释放当前语句,使其可以被再次获取stmtHolder.decrementInUseCount();//如果开启了PSCache,并且当前语句没有发生过异常if (stmt.isPooled() && holder.isPoolPreparedStatements() && stmt.exceptionCount == 0) {//置入语句池holder.getStatementPool().put(stmtHolder);//清空其返回集合stmt.clearResultSet();//取消对这个语句的跟踪holder.removeTrace(stmt);//记录当前语句的的查询峰值(监控用)stmtHolder.setFetchRowPeak(stmt.getFetchRowPeak());//软关闭当前语句stmt.setClosed(true); // soft set close} else if (stmt.isPooled() && holder.isPoolPreparedStatements()) {// the PreparedStatement threw an exception//进入此分支时,则当前语句抛出过异常//清除所有的返回集合stmt.clearResultSet();//删除跟踪holder.removeTrace(stmt);//从语句池中删除这条语句并关闭,因为这条语句不再健康holder.getStatementPool().remove(stmtHolder);} else {try {//Connection behind the statement may be in invalid state, which will throw a SQLException.//In this case, the exception is desired to be properly handled to remove the unusable connection from the pool.//真正关闭当前预编译过的语句stmt.closeInternal();} catch (SQLException ex) {this.handleException(ex, null);throw ex;} finally {//增加计数(关闭了多少预编译语句)holder.getDataSource().incrementClosedPreparedStatementCount();}}
}
经过查阅代码,发现其确实是在语句关闭时进行处理,对一条被预编译过的语句有以下三种处理方式
- 开启PSCache并且这条语句没有抛出过异常时,将其添加进缓存池
- 开启PSCache但是这条语句发生过异常,从缓存池中移除并关闭
- 没有开启PSCache,直接关闭这条SQL
4.为什么官方文档中不推荐在MySQL中开启PSCache
在查询这方面问题时,关于MySQL不同版本有不同的说法,究其原因是因为在MySQL某一版本之前不支持PSCache。关于poolPreparedStatements问题。 #1256
是否要在线上开启可以参考Druid监控中查看PSCache命中数据来决定。
2022-05-12 Druid源码阅读——poolPreparedStatements是如何控制缓存游标的?相关推荐
- Alibaba Druid 源码阅读(二) 数据库连接池实现初步探索
Alibaba Druid 源码阅读(二) 数据库连接池实现初步探索 简介 在上篇文章中,了解了连接池的应用场景和本地运行了示例,本篇文章中,我们尝试来探索下Alibaba Druid数据库连接池的整 ...
- Alibaba Druid 源码阅读(五)数据库连接池 连接关闭探索
Alibaba Druid 源码阅读(五)数据库连接池 连接关闭探索 简介 在上文中探索了数据库连接池的获取,下面接着初步来探索下数据库连接的关闭,看看其中具体执行了那些操作 连接关闭 下面的具体的代 ...
- Alibaba Druid 源码阅读(四) 数据库连接池中连接获取探索
Alibaba Druid 源码阅读(四) 数据库连接池中连接获取探索 简介 上文中分析了数据库连接池的初始化部分,接下来我们来看看获取连接部分的代码 数据库连接池中连接获取 下面的相关的代码,在代码 ...
- Alibaba Druid 源码阅读(三) 数据库连接池初始化探索
Alibaba Druid 源码阅读(三) 数据库连接池初始化探索 简介 上文中探索了Alibaba Druid的连接池初始化和获取连接的关键代码,接下来详细看看初始化部分 数据库连接池初始化 对整个 ...
- Alibaba Druid 源码阅读(一) 数据库连接池初步
Alibaba Druid 源码阅读(一) 数据库连接池初步 简介 本文将初步探索数据库连接池的应用场景,为后面的源码分析做些准备 数据库连接池的应用场景 在没有连接池之前,在使用中,需要访问数据库时 ...
- Druid源码阅读3-DruidDataSource连接池的基本原理
DruidDataSource数据库连接池的的本质,实际上是一个利用ReentrentLock和两个Condition组成的生产者和消费者模型. 1.DruidDataSource中的锁 在Druid ...
- ExoPlayer 源码阅读小记--HLS播放带缓存加载M38U文件过程
基于ExoPlayer 2.17.1源码分析,基本是一边看一边写的流水账,记录下防止以后忘了: 第一步createMediaSource创建HlsMediaSource对象时同时会实例化出HlsPla ...
- 12 哈希表相关类——Live555源码阅读(一)基本组件类
12 哈希表相关类--Live555源码阅读(一)基本组件类 这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 ...
- 12.源码阅读(app启动流程-android api 26)
activity的启动流程之前已经通过源码了解了,那么app的启动流程是怎样的,从我们按下app的图标,到应用启动起来显示出画面,中间都经历了什么? 安卓是基于java的,所以和java有一定的相似性 ...
最新文章
- web本地存储-IndexedDB
- XPath学习:轴(13)——namespace
- tomcat的JK和JK2
- 有人说Julia比Python好,还给出了5个理由
- Linux Kernel中的同步机制的介绍
- 初学PX4之飞控算法
- JeewxBoot微信管家平台源码v1.3
- 通过使用阿里云+vuepress快速搭建静态个人博客网页页面
- Eigen教程(5)之块操作
- 【数据结构笔记13】C实现:判别是否是同一颗二叉搜索树(BST)
- 使 32 位程序使用大于 2GB 的内存
- atitit.DD dragdrop拖拽文件到界面功能 html5 web 跟个java swing c#.net c++ 的总结
- snipaste如何滚动截图_一文解决几乎所有截图需求:我多年来用过的优秀截图软件和插件推荐...
- python广州地图_广东省客户数量地图展示,如何通过python实现?
- 计算机更换硬盘键盘鼠标不好使,安装win7时鼠标键盘不能用怎么办?(完美解决方法)...
- 微信小游戏开发指南(一)什么是微信小游戏
- url中出现“%22”等如何处理?如何判断url中是否有“%22等”?如何获取当前网址?传入多个参数在url上? encodeURL和(js)
- Nginx系列教材 (五)- 和Tomcat进行负载均衡
- 线上配镜新方式:眼镜直通车竞品分析报告
- 摄像头模组介绍和技术指标