git clone .git
mvn clean install -st.skip=true
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version>
</dependency>
<!--自启动Druid管理后台-->
<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.8</version>
</dependency>
# 数据库配置
spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedruid:url: jdbc:mysql://127.0.0.1:3306/jk_test?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&autoReconnect=true&nullCatalogMeansCurrent=trueusername: rootpassword: 12345678driverClassName: sql.cj.jdbc.Driver#初始化连接initial-size: 10#最大活动连接max-active: 100#最小连接池数量min-idle: 10#从池中取连接的最大等待时间,单位ms.max-wait: 60000#开启池的prepared(默认是false,未调整,经过测试,开启后的性能没有关闭的好。)pool-prepared-statements: truemax-pool-prepared-statement-per-connection-size: 20#每n秒运行一次空闲连接回收器time-between-eviction-runs-millis: 60000#池中的连接空闲..后被回收min-evictable-idle-time-millis: 300000#验证使用的SQL语句validation-query: SELECT 1 FROM DUAL# 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除.test-while-idle: true#借出连接时不要测试,否则很影响性能test-on-borrow: falsetest-on-return: falsestat-view-servlet:enabled: trueurl-pattern: /druid/*#login-username: admin#login-password: adminfilter:stat:log-slow-sql: trueslow-sql-millis: 1000merge-sql: truewall:config:multi-statement-allow: true#连接泄漏回收参数,当可用连接数少于3个时才执行,超过时间限制,回收没有用(废弃)的连接(默认为 300秒,调整为180)#getNumIdle() < 2) and (getNumActive() > getMaxActive() - 3)remove-abandoned: true# 连接泄漏回收参数,180秒,泄露的连接可以被删除的超时值remove-abandoned-timeout: 3000# abanded连接时输出错误日志logAbandoned: true
#初始化连接
//DruidDataSource中 448
{String property = Property("druid.initialSize");if (property != null && property.length() > 0) {try {int value = Integer.parseInt(property);this.setInitialSize(value);} catch (NumberFormatException e) {("illegal property 'druid.initialSize'", e);}}
}
// 初始化链接需要小于最大活动连接数量
if (getInitialSize() > maxActive) {throw new IllegalArgumentException("illegal initialSize " + this.initialSize + ", maxActive " + maxActive);
}
#最大活动连接
//DruidDataSource中 470
{String property = Property("druid.maxActive");if (property != null && property.length() > 0) {try {int value = Integer.parseInt(property);this.setMaxActive(value);} catch (NumberFormatException e) {("illegal property 'druid.maxActive'", e);}}}// 设置最大活动连接的代码
lock.lock();
try {// 获取总的活动数量 int allCount = this.poolingCount + this.activeCount;// maxActive 和 allCount 取大的那个 TODO 疑问点,为什么还需要比较all count init的时候初始化直接获取最大的maxActive不就好了吗?是基于配置中心动态配置最大活动数量的考虑吗?if (maxActive > allCount) {tions = tions, maxActive);evictConnections = new DruidConnectionHolder[maxActive];keepAliveConnections = new DruidConnectionHolder[maxActive];} else {tions = tions, allCount);evictConnections = new DruidConnectionHolder[allCount];keepAliveConnections = new DruidConnectionHolder[allCount];}
this.maxActive = maxActive;
} finally {lock.unlock();
}
#最小连接池数量
// 最小连接池的数量
{String property = Property("druid.minIdle");if (property != null && property.length() > 0) {try {int value = Integer.parseInt(property);this.setMinIdle(value);} catch (NumberFormatException e) {("illegal property 'druid.minIdle'", e);}}
}
// 最大活动连接比较if (inited && value > this.maxActive) {throw new IllegalArgumentException("minIdle greater than maxActive, " + maxActive + " < " + this.minIdle);}
#从池中取连接的最大等待时间,单位ms.
{String property = Property("druid.maxWait");if (property != null && property.length() > 0) {try {int value = Integer.parseInt(property);this.setMaxWait(value);} catch (NumberFormatException e) {("illegal property 'druid.maxWait'", e);}}
}
@Override
public DruidPooledConnection getConnection() throws SQLException {return getConnection(maxWait);
}
//创建连接的时候需要传入最大等待时长
public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException {init();
if (filters.size() > 0) {FilterChainImpl filterChain = new FilterChainImpl(this);return filterChain.dataSource_connect(this, maxWaitMillis);} else {return getConnectionDirect(maxWaitMillis);}
}
// 最大等待时间放与 waitNanosLocal
// final long nanos = Nanos(maxWait);
// waitNanosLocal.set(nanos - estimate);
#开启池的prepared(默认是false,未调整,经过测试,开启后的性能没有关闭的好。)
{Boolean value = getBoolean(properties, "druid.poolPreparedStatements");if (value != null) {this.setPoolPreparedStatements0(value);}
}
// 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
if (this.isPoolPreparedStatements()) {buf.append("nn[");for (int i = 0; i < poolingCount; ++i) {DruidConnectionHolder conn = connections[i];if (conn != null) {if (i != 0) {buf.append(",");}buf.append("nt{ntID:");buf.append(System.Connection()));PreparedStatementPool pool = StatementPool();
buf.append(", ntpoolStatements:[");
int entryIndex = 0;try {for (Map.Entry<PreparedStatementKey, PreparedStatementHolder> entry : Map().entrySet()) {if (entryIndex != 0) {buf.append(",");}buf.append("ntt{hitCount:");buf.Value().getHitCount());buf.append(",sql:"");buf.Key().getSql());buf.append(""");buf.append("t}");
entryIndex++;}} catch (ConcurrentModificationException e) {// skip ..}
buf.append("ntt]");
buf.append("nt}");}}buf.append("n]");
}
#要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100
public void setMaxPoolPreparedStatementPerConnectionSize(int maxPoolPreparedStatementPerConnectionSize) {
//为什么要设置大于0的时候开启poolPreparedStatements呢 直接开个参数或者直接true false不可以吗if (maxPoolPreparedStatementPerConnectionSize > 0) {this.poolPreparedStatements = true;} else {this.poolPreparedStatements = false;}
this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;
}// PreparedStatementPool 使用到这个参数,如果 <0 默认pool的 LRUCache map 为16 避免扩容??
public PreparedStatementPool(DruidConnectionHolder holder){this.dataSource = DataSource();int initCapacity = DataSource().getMaxPoolPreparedStatementPerConnectionSize();if (initCapacity <= 0) {initCapacity = 16;}map = new LRUCache(initCapacity);
}
#每n秒运行一次空闲连接回收器
{String property = Property("druid.timeBetweenEvictionRunsMillis");if (property != null && property.length() > 0) {try {long value = Long.parseLong(property);this.setTimeBetweenEvictionRunsMillis(value);} catch (NumberFormatException e) {("illegal property 'druid.timeBetweenEvictionRunsMillis'", e);}}
}
// DuridDataSource#init判断保持连接的的时间小于最小的空闲时间 异常
if (keepAlive && keepAliveBetweenTimeMillis <= timeBetweenEvictionRunsMillis) {throw new SQLException("keepAliveBetweenTimeMillis must be grater than timeBetweenEvictionRunsMillis");
}
//当连接池初始化时,会初始化一个定时清除空闲连接的任务DestroyTask,该任务默认是1分钟执行一次(使用timeBetweenEvictionRunsMillis参数设置)
protected void createAndStartDestroyThread() {destroyTask = new DestroyTask();
if (destroyScheduler != null) {//轮训销毁时间 定时清除空闲连接的任务long period = timeBetweenEvictionRunsMillis;if (period <= 0) {period = 1000;}destroySchedulerFuture = destroyScheduler.scheduleAtFixedRate(destroyTask, period, period,TimeUnit.MILLISECONDS);untDown();return;}
String threadName = "Druid-ConnectionPool-Destroy-" + System.identityHashCode(this);destroyConnectionThread = new DestroyConnectionThread(threadName);destroyConnectionThread.start();
}
#池中的连接空闲..后被回收
{String property = Property("druid.minEvictableIdleTimeMillis");if (property != null && property.length() > 0) {try {long value = Long.parseLong(property);this.setMinEvictableIdleTimeMillis(value);} catch (NumberFormatException e) {("illegal property 'druid.minEvictableIdleTimeMillis'", e);}}
}
//定时清除空闲连接的任务, destroySchedulerFuture = destroyScheduler.scheduleAtFixedRate(destroyTask, period, period, TimeUnit.MILLISECONDS);定时任务中会判断连接池的连接是否满足关闭的条件,如果满足则关闭,满足的条件如下:
//关闭条件,空闲时间大于minEvictableIdleTimeMillis,并且空闲连接大于minIdle,
// 其中checkCount为poolingCount - minIdle,即可能被关闭的连接数量
// 或者空闲时间大于maxEvictableIdleTimeMillis
if (idleMillis >= minEvictableIdleTimeMillis) {if (checkTime && i < checkCount) {evictConnections[evictCount++] = connection;continue;} else if (idleMillis > maxEvictableIdleTimeMillis) {evictConnections[evictCount++] = connection;continue;}
}
本文发布于:2024-01-28 07:33:30,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17063984145820.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |