您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
稳,从数据库连接池 testOnBorrow 看架构设计
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
稳,从数据库连接池 testOnBorrow 看架构设计
完成设置321
2023-06-20
IP归属:北京
8200浏览
> 本文从 Commons DBCP testOnBorrow 的作用机制着手,管中窥豹,从一点去分析数据库连接池获取的过程以及架构分层设计。 > > 以下内容会按照每层的作用,贯穿分析整个调用流程。 ## 1️⃣框架层 commons-pool > The indication of whether objects will be **validated before being borrowed** from the pool. > > If the object fails to validate, it will be dropped from the pool, and we will attempt to borrow another. > > **testOnBorrow 不是 dbcp 定义的,是commons-pool 定义的**。commons-pool 详细的定义了资源池使用的一套规范和运行流程。 ```java /** * Borrow an object from the pool. get object from 资源池 * @see org.apache.commons.pool2.impl.GenericObjectPool#borrowObject(long) */ public T borrowObject(final long borrowMaxWaitMillis) throws Exception { PooledObject<T> p = null; // if validation fails, the instance is destroyed and the next available instance is examined. // This continues until either a valid instance is returned or there are no more idle instances available. while (p == null) { // If there is one or more idle instance available in the pool, // then an idle instance will be selected based on the value of getLifo(), activated and returned. p = idleObjects.pollFirst(); if (p != null) { // 设置 testOnBorrow 就会进行可用性校验 if (p != null && (getTestOnBorrow() || create && getTestOnCreate())) { boolean validate = false; Throwable validationThrowable = null; try { // 具体的校验实现由实现类完成。 // see org.apache.commons.dbcp2.PoolableConnectionFactory validate = factory.validateObject(p); } catch (final Throwable t) { PoolUtils.checkRethrow(t); validationThrowable = t; } if (!validate) { try { // 如果校验异常,会销毁该资源。 // obj is not valid and should be dropped from the pool destroy(p); destroyedByBorrowValidationCount.incrementAndGet(); } catch (final Exception e) { // Ignore - validation failure is more important } p = null; } } } } return p.getObject(); } ``` ## 2️⃣应用层 commons-dbcp > dbcp 是特定于管理数据库连接的资源池。 > > **PoolableConnectionFactory** is a PooledObjectFactory > > PoolableConnection is a PooledObject ```java /** * @see PoolableConnectionFactory#validateObject(PooledObject) */ @Override public boolean validateObject(final PooledObject<PoolableConnection> p) { try { /** * 检测资源池对象的创建时间,是否超过生存时间 * 如果超过 maxConnLifetimeMillis, 不再委托数据库连接进行校验,直接废弃改资源 * @see PoolableConnectionFactory#setMaxConnLifetimeMillis(long) */ validateLifetime(p); // 委托数据库连接进行自我校验 validateConnection(p.getObject()); return true; } catch (final Exception e) { return false; } } /** * 数据库连接层的校验。具体到是否已关闭、是否与 server 连接可用 * @see Connection#isValid(int) */ public void validateConnection(final PoolableConnection conn) throws SQLException { if(conn.isClosed()) { throw new SQLException("validateConnection: connection closed"); } conn.validate(_validationQuery, _validationQueryTimeout); } ``` ## 3️⃣基础层 mysql-connector-java > Returns true if the connection has not been closed and is still valid. > > 这个是 java.sql.Connection 定义的规范。具体实现根据对应数据库的driver 来完成。使用某种机制用来探测连接是否可用。 ```java /** * 调用 com.mysql.jdbc.MysqlIO, 发送ping 请求,检测是否可用 * 对比 H2 数据库,是通过获取当前事务级别来检测连接是否可以。但是忽略了 timeout 配置,毕竟是 demo 数据库 😅 */ public synchronized boolean isValid(int timeout) throws SQLException { if (this.isClosed()) { return false; } else { try { this.pingInternal(false, timeout * 1000); return true; } catch (Throwable var5) { return false; } } } ``` 参考:[MySQL 的连接时长控制--interactive_timeout和wait_timeout_翔云123456的博客-CSDN博客](https://blog.csdn.net/lanyang123456/article/details/102535434) ## 总结 - commons-pool 定义资源的**完整声明周期接口**,包括:makeObject、activateObject、validateObject、passivateObject、destoryObject。资源池管理对象,通过实现这些接口即可实现资源控制。参考:org.apache.commons.pool2.PooledObjectFactory - 在校验过程中,牵涉到很多时间,包括资源池对象的创建时间、生存时间、数据库连接的超时时间、Mysql 连接空闲超时时间等。**不同层为了服务可靠性,提供不同的时间配置**。校验也是层层递进,最终委托到最底层来判断。 - 校验过程中,对于连接也会由是否已关闭的校验(**isClosed()**)。包括PoolableConnection#isClosed, Connection#isClosed, Socket#isClosed。 同样也是层层保障,确保整个架构的可靠。💪 - **定义一套完整严谨的规范和标准,比实现一个具体的功能或者特性要求更高** 🎯。commons-pool 和 jdbc 定义了规范,commons-dbcp 和 mysql-connector-java 完成了具体的实现。有了规范和接口,组件和框架的对接和兼容才变为可能。 ## more 理解高可用 > 在阅读 MySQL Driver 源码过程中,有个点要特别记录下。以 MySQL Driver 创建连接为例,用重试连接实现可用性,这就是高可用。🎯 > 高可用不是一个口号,也不是复杂的概念和公式。能够实实在在体系化的解决一类问题就是架构的目的。结合上述的架构分层,如果解决问题的方案通用性好,并且实现很优雅,就是好的架构。 ```java // autoReconnect public void createNewIO(boolean isForReconnect) throws SQLException { synchronized (getConnectionMutex()) { // jdbc.url autoReconnect 指定为 true,识别为 HighAvailability。emmm..... 🙉 if (!getHighAvailability()) { connectOneTryOnly(isForReconnect, mergedProps); return; } // maxReconnects 默认为 3,重试失败的提示就是: Attempted reconnect 3 times. Giving up. connectWithRetries(isForReconnect, mergedProps); } } ``` 引流: [H2 数据库 索引和存储原理 Code Insight](http://xingyun.jd.com/shendeng/article/detail/15199) 😀
上一篇:全栈角度看分页处理
下一篇:推荐几款可以大幅提高开发效率的vscode插件
完成设置321
文章数
7
阅读量
1155
作者其他文章
01
稳,从数据库连接池 testOnBorrow 看架构设计
本文从 Commons DBCP testOnBorrow 的作用机制着手,管中窥豹,从一点去分析数据库连接池获取的过程以及架构分层设计。以下内容会按照每层的作用,贯穿分析整个调用流程。1️⃣框架层 commons-poolThe indication of whether objects will be validated before being borrowed from the pool.
01
分布式数据库 Join 查询设计与实现浅析
相对于单例数据库的查询操作,分布式数据查询会有很多技术难题。本文记录 Mysql 分库分表 和 Elasticsearch Join 查询的实现思路,了解分布式场景数据处理的设计方案。文章从常用的关系型数据库 MySQL 的分库分表Join 分析,再到非关系型 ElasticSearch 来分析 Join 实现策略。逐步深入Join 的实现机制。①Mysql 分库分表 Join 查询场景分库分表场
01
这问题巧了,SpringMVC 不同参数处理机制引发的思考
这个问题非常有趣,不是SpringMVC 的问题,是实际开发中混合使用了两种请求方式暴露出来的。问题场景功能模块中,提供两个 Http 服务。一个是列表查询(application/json 请求),一个是列表导出(表单请求)。运行环境发现个问题:MVC model 新添加的属性,类似的 Http 请求,一个有值,一个没有代码如下:/** * application/json 请求。 这种情况 p
01
h2database BTree 设计实现与查询优化思考
h2database 是使用Java 编写的开源数据库,兼容ANSI-SQL89。即实现了常规基于 BTree 的存储引擎,又支持日志结构存储引擎。功能非常丰富(死锁检测机制、事务特性、MVCC、运维工具等),数据库学习非常好的案例。本文理论结合实践,通过BTree 索引的设计和实现,更好的理解数据库索引相关的知识点以及优化原理。BTree 实现类h2database 默认使用的 MVStore
完成设置321
文章数
7
阅读量
1155
作者其他文章
01
分布式数据库 Join 查询设计与实现浅析
01
这问题巧了,SpringMVC 不同参数处理机制引发的思考
01
h2database BTree 设计实现与查询优化思考
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号