当前位置: 首页> 健康> 知识 > 企业法治建设工作报告_网上写作如何投稿赚钱_主要推广手段免费_uc信息流广告投放

企业法治建设工作报告_网上写作如何投稿赚钱_主要推广手段免费_uc信息流广告投放

时间:2025/8/8 15:34:13来源:https://blog.csdn.net/qq_29569183/article/details/146987022 浏览次数:0次
企业法治建设工作报告_网上写作如何投稿赚钱_主要推广手段免费_uc信息流广告投放

目录

为什么需要JDBC连接池

Tomcat JDBC Pool 相关参数

1. 基本配置

2. 连接池大小控制

3. 连接验证与测试

4. 空闲连接回收

5. 连接泄漏与超时

Tomcat JDBC Pool 源码分析(tomcat 8.5.3)

DataSourceFactory

DataSource

ConnectionPool

PoolCleaner


对于JAVA开发者来说,JDBC肯定都比较熟悉,它其实是Java提供了一套用于数据库操作的接口API,Java程序员只需要面向这套接口编程即可,不同的数据库厂商需要针对这套接口提供不同的实现。

为什么需要JDBC连接池

使用传统的jdbc做开发时,一方面频,繁的进行数据库连接操作将占用很多的系统资源,另一方面,每次拿到connection使用完都要主动去断开,那如果程序出现异常导致链接没有关闭,就会发生内存会泄露,因此可以发现使用jdbc开发时在连接管理上是存在风险的。另外,用传统的连接方法无法控制程序中创建的连接数量,如果连接过多也会导致内存泄漏。

那JDBC连接池的作用,就是可以避免频繁创建连接,帮我们做连接的生命周期管理,以及在请求较大时控制应用内连接的数量防止出现崩溃。

目前java生态里主流的JDBC连接池有HikariCP,Druid等,还有本文写的Tomcat JDBC Pool。

Tomcat JDBC Pool 相关参数

下面列举了一些基本参数和连接管理方面检测机制相关的参数

1. 基本配置

  • driverClassName
    数据库驱动类名(如 com.mysql.jdbc.Driver)。
  • url
    数据库连接 URL(如 jdbc:mysql://localhost:3306/mydb)。
  • username
    数据库用户名。
  • password
    数据库密码。

2. 连接池大小控制

  • initialSize
    连接池初始化时创建的连接数(默认 0)。
  • maxActive
    最大活跃连接数(默认 100)。
  • maxIdle
    最大空闲连接数(默认与 maxActive 相同)。
  • minIdle
    最小空闲连接数(默认 0)。
  • maxWait
    获取连接的最大等待时间(毫秒,默认 30000,超时抛异常)。

3. 连接验证与测试

  • testOnBorrow
    从池中获取连接时是否验证有效性(默认 false)。
  • testOnReturn
    归还连接时是否验证有效性(默认 false)。
  • testWhileIdle
    空闲时是否定期验证连接(默认 false)。
  • validationQuery
    用于验证连接的 SQL 查询(如 SELECT 1)。
  • validationQueryTimeout
    验证查询的超时时间(秒,默认 -1 表示无限制)。

4. 空闲连接回收

  • timeBetweenEvictionRunsMillis
    空闲连接检查线程的运行间隔(毫秒,默认 5000)。
  • minEvictableIdleTimeMillis
    连接被回收前的最小空闲时间(默认 60000)。
  • numTestsPerEvictionRun
    每次检查回收的空闲连接数(默认使用所有空闲连接)。

5. 连接泄漏与超时

  • removeAbandoned
    是否自动回收泄露的连接(默认 false)。
  • removeAbandonedTimeout
    连接被标记为泄露的时间阈值(秒,默认 60)。
  • logAbandoned
    是否记录泄露连接的堆栈信息(默认 false)。

     

Tomcat JDBC Pool 源码分析(tomcat 8.5.3)

下面简单分析下tomcat连接池是如何创建,又是如何实现连接检测的。

DataSourceFactory

DataSourceFactory是Tomcat JDBC Pool 中用来创建DataSource的工厂类,这个类在org.apache.tomcat.jdbc.pool包下。

下面是类中与连接池创建相关的部分代码片段:

public DataSource createDataSource(Properties properties) throws Exception {return createDataSource(properties,null,false);
}public DataSource createDataSource(Properties properties,Context context, boolean XA) throws Exception {PoolConfiguration poolProperties = DataSourceFactory.parsePoolProperties(properties);if (poolProperties.getDataSourceJNDI()!=null && poolProperties.getDataSource()==null) {performJNDILookup(context, poolProperties);}org.apache.tomcat.jdbc.pool.DataSource dataSource = XA? new org.apache.tomcat.jdbc.pool.XADataSource(poolProperties) : new org.apache.tomcat.jdbc.pool.DataSource(poolProperties);//创建连接池dataSource.createPool();return dataSource;
}

可以看到 DataSourceFactory.createDataSource 方法返回一个DataSource实例,DataSource初始化后调用了 createPool 方法来初始化连接池相关的组件。

DataSource

DataSource是内置了数据源连接池 ConnectionPool 的对象,基于JDBC标准对外提供了一些方法。

Tomcat JDBC Pool 中支持两种DataSource类型,一种是普通DataSource,另一种是XADataSourced。

ConnectionPool

ConnectionPool 就是连接池最核心的资源对象,但是他不会直接对外暴露,而是被包装在上面说的DataSource中,开发过程中通常先获取到的是DataSource对象实例。

了解了DataSource 和 ConnectionPool 后,继续来看DataSourceFactory.createDataSource 方法中的createPool方法逻辑,这个方法在DataSource或XADataSourced共同的父类DataSourceProxy,打开DataSourceProxy类可以进一步看具体的方法内容:

public ConnectionPool createPool() throws SQLException {if (pool != null) {return pool;} else {return pCreatePool();}
}/*** Sets up the connection pool, by creating a pooling driver.*/
private synchronized ConnectionPool pCreatePool() throws SQLException {if (pool != null) {return pool;} else {pool = new ConnectionPool(poolProperties);return pool;}
}
public ConnectionPool(PoolConfiguration prop) throws SQLException {init(prop);
}

 createPool  方法最终后调用到 init 方法:

protected void init(PoolConfiguration properties) throws SQLException {poolProperties = properties;//make sure the pool is properly configuredcheckPoolConfiguration(properties);//make space for 10 extra in case we flow over a bitbusy = new LinkedBlockingQueue<>();//busy = new FairBlockingQueue<PooledConnection>();//make space for 10 extra in case we flow over a bitif (properties.isFairQueue()) {idle = new FairBlockingQueue<>();//idle = new MultiLockFairBlockingQueue<PooledConnection>();//idle = new LinkedTransferQueue<PooledConnection>();//idle = new ArrayBlockingQueue<PooledConnection>(properties.getMaxActive(),false);} else {idle = new LinkedBlockingQueue<>();}initializePoolCleaner(properties);//create JMX MBeanif (this.getPoolProperties().isJmxEnabled()) createMBean();//Parse and create an initial set of interceptors. Letting them know the pool has started.//These interceptors will not get any connection.PoolProperties.InterceptorDefinition[] proxies = getPoolProperties().getJdbcInterceptorsAsArray();for (int i=0; i<proxies.length; i++) {try {if (log.isDebugEnabled()) {log.debug("Creating interceptor instance of class:"+proxies[i].getInterceptorClass());}JdbcInterceptor interceptor = proxies[i].getInterceptorClass().getConstructor().newInstance();interceptor.setProperties(proxies[i].getProperties());interceptor.poolStarted(this);}catch (Exception x) {log.error("Unable to inform interceptor of pool start.",x);if (jmxPool!=null) jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_INIT, getStackTrace(x));close(true);SQLException ex = new SQLException();ex.initCause(x);throw ex;}}//initialize the pool with its initial set of membersPooledConnection[] initialPool = new PooledConnection[poolProperties.getInitialSize()];try {for (int i = 0; i < initialPool.length; i++) {initialPool[i] = this.borrowConnection(0, null, null); //don't wait, should be no contention} //for} catch (SQLException x) {log.error("Unable to create initial connections of pool.", x);if (!poolProperties.isIgnoreExceptionOnPreLoad()) {if (jmxPool!=null) jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_INIT, getStackTrace(x));close(true);throw x;}} finally {//return the members as idle to the poolfor (int i = 0; i < initialPool.length; i++) {if (initialPool[i] != null) {try {this.returnConnection(initialPool[i]);}catch(Exception x){/*NOOP*/}} //end if} //for} //catchclosed = false;
}

这个方法中执行了 initializePoolCleaner 这个方法

 public void initializePoolCleaner(PoolConfiguration properties) {//if the evictor thread is supposed to run, start it nowif (properties.isPoolSweeperEnabled()) {poolCleaner = new PoolCleaner(this, properties.getTimeBetweenEvictionRunsMillis());poolCleaner.start();} //end if}

initializePoolCleaner 方法的逻辑是初始化一个PoolCleaner,然后启动它。

注意初始化这个构造器,传入了一个关键参数:

betweenEvictionRunsMillis

这个参数用来指定对于空闲链接检测的任务多久执行一次,默认值是5000ms,默认值实在 org.apache.tomcat.jdbc.pool.PoolProperties 类中定义的固定值,如果外部设置了会覆盖。

PoolCleaner

PoolCleaner 是 ConnectionPool 中的一个内部静态类。这个类继承TimerTask ,实例化后其实是一个线程任务,Tomcat JDBC Pool 就是通过启动这个定时任务来实现连接池中的各种检测功能。

run方法中就是检测任务的具体逻辑,包括:

1.对最小连接数的维护,数量少于最小连接数则新建补充,数量多了则销毁多余的。

2.对空闲链接的检测,如果 testWhileIdle 参数设置为true,那在任务每次执行时会获取一定数量的链接,判断是否可用,如果不可用就销毁。

 protected static class PoolCleaner extends TimerTask {protected WeakReference<ConnectionPool> pool;protected long sleepTime;PoolCleaner(ConnectionPool pool, long sleepTime) {this.pool = new WeakReference<>(pool);this.sleepTime = sleepTime;if (sleepTime <= 0) {log.warn("Database connection pool evicter thread interval is set to 0, defaulting to 30 seconds");this.sleepTime = 1000 * 30;} else if (sleepTime < 1000) {log.warn("Database connection pool evicter thread interval is set to lower than 1 second.");}}@Overridepublic void run() {ConnectionPool pool = this.pool.get();if (pool == null) {stopRunning();} else if (!pool.isClosed()) {try {if (pool.getPoolProperties().isRemoveAbandoned()|| pool.getPoolProperties().getSuspectTimeout() > 0)pool.checkAbandoned();if (pool.getPoolProperties().getMinIdle() < pool.idle.size())pool.checkIdle();if (pool.getPoolProperties().isTestWhileIdle())pool.testAllIdle();} catch (Exception x) {log.error("", x);}}}public void start() {registerCleaner(this);}public void stopRunning() {unregisterCleaner(this);}}

关键字:企业法治建设工作报告_网上写作如何投稿赚钱_主要推广手段免费_uc信息流广告投放

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: