四个主要的连接池介绍!(建议收藏!)
连接池这里主要介绍这些知识点~????数据库连接池回忆下 JDBC 的写法 ✍ ,就能感受到连接池的好处了~void jdbcTest() throws ClassNotFoundException {String url = "jdbc:mysql://localhost:3306/db";String username = "";String password = "";Class.forNa
连接池
这里主要介绍这些知识点~😝
数据库连接池
回忆下 JDBC
的写法 ✍ ,就能感受到连接池的好处了~
void jdbcTest() throws ClassNotFoundException {
String url = "jdbc:mysql://localhost:3306/db";
String username = "";
String password = "";
Class.forName("com.mysql.jdbc.Driver");
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = DriverManager.getConnection(url, username, password);
preparedStatement= connection.prepareStatement("select * from User where name=?");
preparedStatement.setString(1, "Java4ye");
preparedStatement.executeQuery();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
try {
if (preparedStatement!=null){
preparedStatement.close();
}
if (connection != null){
connection.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
可以发现在这种模式下,每次都要去创建和销毁连接,造成了很大的浪费。我们可以尝试去优化下,
比如,参考上面 线程池的思想
- 用完不销毁,先存起来;
- 一开始的时候,就初始化多个连接;
- 给连接加上最大空闲时间限定;
- 加上最大连接数限定;
…
最后,你可以发现,你封装了一个简单的连接池了😄
数据库连接池原理图
那数据库连接池有啥作用呢?
负责连接的管理,分配和释放,当连接的空闲时间超过最大空闲时间时,会释放连接,避免连接泄露
常见的数据库连接池
这里就主要说说这个 HikariCP
和 Druid
了,其他的如 C3P0
,DBCP
等就不说啦(主要是没用上 哈哈哈)
HikariCP
HikariCP
是 Springboot2
开始默认使用的连接池(官方认证~🐷),速度最快
优点:
- 字节码精简 :优化代码,编译后的字节码最少,这样,CPU缓存可以加载更多的程序代码;
- 优化代理和拦截器 :减少代码,例如 HikariCP 的 Statement proxy 只有100行代码,只有 BoneCP 的十分之一;
- 自定义数组类型(FastStatementList)代替ArrayList :避免每次get()调用都要进行range check,避免调用remove()时的从头到尾的扫描;
- 自定义集合类型(ConcurrentBag) :提高并发读写的效率;
- 其他针对 BoneCP 缺陷的优化。
源码
有机会可以研究看看 ~
下面这段代码是 HikariCP
中 getConnection()
的源码~ 给大家感受下👇 ([[HikariCP 源码]])
// ***********************************************************************
// DataSource methods
// ***********************************************************************
/** {@inheritDoc} */
@Override
public Connection getConnection() throws SQLException
{
if (isClosed()) {
throw new SQLException("HikariDataSource " + this + " has been closed.");
}
if (fastPathPool != null) {
return fastPathPool.getConnection();
}
// See http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
HikariPool result = pool;
if (result == null) {
synchronized (this) {
result = pool;
if (result == null) {
validate();
LOGGER.info("{} - Starting...", getPoolName());
try {
pool = result = new HikariPool(this);
this.seal();
}
catch (PoolInitializationException pie) {
if (pie.getCause() instanceof SQLException) {
throw (SQLException) pie.getCause();
}
else {
throw pie;
}
}
LOGGER.info("{} - Start completed.", getPoolName());
}
}
}
return result.getConnection();
}
看下来就捕捉到单例设计模式的影子~
小伙伴们可以看看之前这篇 《一文带你看遍单例模式的八个例子,面试再也不怕被问了》
是不是用到了单例的 双重检查锁模式 😄
配置属性
有这么多!🐷
private static final char[] ID_CHARACTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
private static final long CONNECTION_TIMEOUT = SECONDS.toMillis(30);
private static final long VALIDATION_TIMEOUT = SECONDS.toMillis(5);
private static final long IDLE_TIMEOUT = MINUTES.toMillis(10);
private static final long MAX_LIFETIME = MINUTES.toMillis(30);
private static final int DEFAULT_POOL_SIZE = 10;
private static boolean unitTest = false;
// Properties changeable at runtime through the HikariConfigMXBean
//
private volatile String catalog;
private volatile long connectionTimeout;
private volatile long validationTimeout;
private volatile long idleTimeout;
private volatile long leakDetectionThreshold;
private volatile long maxLifetime;
private volatile int maxPoolSize;
private volatile int minIdle;
private volatile String username;
private volatile String password;
// Properties NOT changeable at runtime
//
private long initializationFailTimeout;
private String connectionInitSql;
private String connectionTestQuery;
private String dataSourceClassName;
private String dataSourceJndiName;
private String driverClassName;
private String exceptionOverrideClassName;
private String jdbcUrl;
private String poolName;
private String schema;
private String transactionIsolationName;
private boolean isAutoCommit;
private boolean isReadOnly;
private boolean isIsolateInternalQueries;
private boolean isRegisterMbeans;
private boolean isAllowPoolSuspension;
private DataSource dataSource;
private Properties dataSourceProperties;
private ThreadFactory threadFactory;
private ScheduledExecutorService scheduledExecutor;
private MetricsTrackerFactory metricsTrackerFactory;
private Object metricRegistry;
private Object healthCheckRegistry;
private Properties healthCheckProperties;
private volatile boolean sealed;
默认值👉
简单介绍下上面红框中的配置:
CONNECTION_TIMEOUT = SECONDS.toMillis(30); // 连接超时,默认 30 秒
VALIDATION_TIMEOUT = SECONDS.toMillis(5); // 验证连接有效性的超时时间,默认 5 秒
IDLE_TIMEOUT = MINUTES.toMillis(10); // 空闲连接存活最大时间 , 默认 10 分钟
MAX_LIFETIME = MINUTES.toMillis(30); // 连接最大存活时间 , 默认 30 分钟
DEFAULT_POOL_SIZE = 10; // 默认连接池大小 , 10
一些常见的配置
spring:
datasource:
hikari:
# 最小空闲连接数量
minimum-idle: 5
# 连接超时,默认 30 秒
connection-timeout: 30
# 空闲连接存活最大时间 , 默认 10 分钟
idle-timeout: 3
# 连接池最大连接数,默认是10
maximum-pool-size: 20
# 连接池名称
pool-name: 4yePool_HikariCP
# 自动提交事务,默认 true
auto-commit: true
# 连接最长的生命周期,默认 30 分钟
max-lifetime: 1800
嘿嘿 再来介绍下阿里的 Druid
🐂
Druid
阿里云计算平台团队出品,为监控而生的数据库连接池
下面那个是 Apache 的 Druid ,两个是不同的! 一个是连接池,一个是数据库~
Apache Druid是一个高性能的实时分析型数据库
Druid连接池介绍
主要特点是监控,提供了web页面给我们监控 SQL,Session,Spring 等等~ 而且据说监控对性能的影响很小🐷
小伙伴们点击下面连接就可以看到啦~👇
常见问题
Druid
常见问题 可以在 github
的 wiki
中查看😃
很多问题都可以在上面找到答案~ 比如
…
功能:
如图~ (原来这么多!)
优点:
经历了阿里大规模验证!😄
是 阿里巴巴内部唯一使用的连接池,在内部数据库相关中间件 TDDL/DRDS 都内置使用强依赖了Druid连接池
Springboot 集成 druid 👇
这里配置超级全,大家就直接看文档就好啦 😄
HttpClient连接池
http请求过程
如果所示,这是一个 Http 请求的大致过程
HTTP keep-alive 机制
上面的请求也是一个短链接的过程,每次请求结束就关闭连接了,很浪费资源,而长连接和短链接的最主要区别就是这个 keep-alive
机制。
这里简单说下这个 长连接 keep-alive
在 http1.0 中 ,请求头中是默认没有这个 Connection: keep-alive
而在 http1.1 中 , 请求头中默认是带上这个的。
TCP keep-alive
(保活)机制
除了应用层的 HTTP
有这个机制外,传输层的 TCP
也有。
TCP
保活机制的主要特点是 每隔一段时间会通过心跳包检测对端是否存活
这里参考下 linux
。
我们可以通过 sysctl -a | grep keepalive
查看内核参数
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_time = 7200
- 保活时间(tcp_keepalive_time)默认:7200 秒
- 保活时间间隔(tcp_keepalive_intvl)默认:75 秒
- 探测循环次数(tcp_keepalive_probes)默认:9 次
这里的意思是,在两个钟(7200秒)内没有收到报文的话,会每隔75秒发送一个 保活探测包 ,重复9 次,直到收到响应,到达9次的话,如果还是没有响应,就会关闭连接。
保活机制的区别
HTTP
是为了复用连接 , 而 TCP
是为了保证对端存活,如果对端挂了的话,会关闭 TCP
连接。
连接池
这里和大家扯这么多主要是为了简单说说这个 Http
建立连接的麻烦 ,哈哈哈 频繁的创建和销毁连接很不友好。(说来说去都是这句话😝)
而且在 HTTP
的背后,还有着这么一个保活机制,这也意味着我们的连接池在实现这个连接的复用时,还要考虑这个Keep-alive
机制~
所以。。说了这么多,还是来看看这个 apache
的 httpcomponents
中的 httpclient
有啥秘密叭 😝
HttpClient 介绍
总体上分为下面七大块
- Fundamentals
- Connection management
- HTTP state management
- HTTP authentication
- Fluent API
- HTTP Caching
- Advanced topics
Keep Alive 策略
官网介绍
The HTTP specification does not specify how long a persistent connection may be and should be kept alive. Some HTTP servers use a non-standard
Keep-Alive
header to communicate to the client the period of time in seconds they intend to keep the connection alive on the server side. HttpClient makes use of this information if available.If the
Keep-Alive
header is not present in the response, HttpClient assumes the connection can be kept alive indefinitely.可以看到如果返回头中没有设置这个 Keep-Avlie 的话,HttpClient 会认为它是无限期存活的!
However, many HTTP servers in general use are configured to drop persistent connections after a certain period of inactivity in order to conserve system resources, quite often without informing the client. In case the default strategy turns out to be too optimistic, one may want to provide a custom keep-alive strategy.
这里直接用官网的简单例子运行下,从debug日志中可以看到,没配置的话,确实输出了 kept alive indefinitely
代码 demo
public static void main(String[] args) throws IOException {
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet("http://www.baidu.com");
CloseableHttpResponse response1 = httpclient.execute(httpGet);
// The underlying HTTP connection is still held by the response object
// to allow the response content to be streamed directly from the network socket.
// In order to ensure correct deallocation of system resources
// the user MUST call CloseableHttpResponse#close() from a finally clause.
// Please note that if response content is not fully consumed the underlying
// connection cannot be safely re-used and will be shut down and discarded
// by the connection manager.
try {
System.out.println(response1.getStatusLine());
HttpEntity entity1 = response1.getEntity();
// do something useful with the response body
// and ensure it is fully consumed
EntityUtils.consume(entity1);
} finally {
response1.close();
}
HttpPost httpPost = new HttpPost("http://www.baidu.com");
List <NameValuePair> nvps = new ArrayList <NameValuePair>();
nvps.add(new BasicNameValuePair("username", "vip"));
nvps.add(new BasicNameValuePair("password", "secret"));
httpPost.setEntity(new UrlEncodedFormEntity(nvps));
CloseableHttpResponse response2 = httpclient.execute(httpPost);
try {
System.out.println(response2.getStatusLine());
HttpEntity entity2 = response2.getEntity();
// do something useful with the response body
// and ensure it is fully consumed
EntityUtils.consume(entity2);
} finally {
response2.close();
}
}
源码分析
嘿嘿 ,来都来了,就顺手 debug 分析下上面这个 execute 方法~
从下图中我们可以发现,这里会去调用 reuseStrategy.keepAlive()
做判断,接着通过keepAliveStrategy.getKeepAliveDuration
去获取该连接的存活时间 🐷
这两个策略分别为 重用策略 ConnectionReuseStrategy
和 保活策略 ConnectionKeepAliveStrategy
省去debug步骤~ 🐷
我们直接来到这个默认的重用策略 DefaultConnectionReuseStrategy
,来看看这里是怎么去判断这个连接可以不可以重用叭~
keepAlive
源码
public boolean keepAlive(HttpResponse response, HttpContext context) {
Args.notNull(response, "HTTP response");
Args.notNull(context, "HTTP context");
if (response.getStatusLine().getStatusCode() == 204) {
Header clh = response.getFirstHeader("Content-Length");
if (clh != null) {
try {
int contentLen = Integer.parseInt(clh.getValue());
if (contentLen > 0) {
return false;
}
} catch (NumberFormatException var11) {
}
}
Header teh = response.getFirstHeader("Transfer-Encoding");
if (teh != null) {
return false;
}
}
HttpRequest request = (HttpRequest)context.getAttribute("http.request");
if (request != null) {
try {
BasicTokenIterator ti = new BasicTokenIterator(request.headerIterator("Connection"));
while(ti.hasNext()) {
String token = ti.nextToken();
if ("Close".equalsIgnoreCase(token)) {
return false;
}
}
} catch (ParseException var13) {
return false;
}
}
ProtocolVersion ver = response.getStatusLine().getProtocolVersion();
Header teh = response.getFirstHeader("Transfer-Encoding");
if (teh != null) {
if (!"chunked".equalsIgnoreCase(teh.getValue())) {
return false;
}
} else if (this.canResponseHaveBody(request, response)) {
Header[] clhs = response.getHeaders("Content-Length");
if (clhs.length != 1) {
return false;
}
Header clh = clhs[0];
try {
long contentLen = Long.parseLong(clh.getValue());
if (contentLen < 0L) {
return false;
}
} catch (NumberFormatException var10) {
return false;
}
}
HeaderIterator headerIterator = response.headerIterator("Connection");
if (!headerIterator.hasNext()) {
headerIterator = response.headerIterator("Proxy-Connection");
}
if (headerIterator.hasNext()) {
try {
TokenIterator ti = new BasicTokenIterator(headerIterator);
boolean keepalive = false;
while(ti.hasNext()) {
String token = ti.nextToken();
if ("Close".equalsIgnoreCase(token)) {
return false;
}
if ("Keep-Alive".equalsIgnoreCase(token)) {
keepalive = true;
}
}
if (keepalive) {
return true;
}
} catch (ParseException var12) {
return false;
}
}
return !ver.lessEquals(HttpVersion.HTTP_1_0);
}
哈哈哈 不想看分析的话 往下滑动一点点,有图~ 😝
分析:
-
判断
HTTP
响应头中的状态码是不是 204 ,是的话进入下面的判断-
响应头中是否有
Content-Length
,有的话看它的值是否大于0,大于的时候 不重用 -
响应头 中是否有
Transfer-Encoding
,有的话 不重用( Tip: 204 表示 No Content:服务器成功处理了请求,但没返回任何内容 ,但是上面两种都表示还有内容,是错误的❌,所以不重用)
-
-
判断 请求头中是否有
Connection:Close
,有的话也 不重用 -
判断 响应头 中是否有
Transfer-Encoding
,有的话看它的值,如果值 不等于chunked
, 不重用 -
判断 响应头中是否有
Content-Length
, 有的话看它的值,如果值 小于 0 , 不重用 -
判断 响应头中是否有
Connection
或者Proxy-Connection
其中的一个 ,有的话看它的值,如果是Close
, 不重用,如果是Keep-Alive
重用 -
最后,如果上面的判断条件都不成立,会判断
http
的版本是不是 小于 1.0,是的话也返回 false
贴心的 4ye 居然画了这么详细的 流程图😝 (感谢老板的 一键三连 😝)
这里要注意,连接池中有两个默认的参数很重要(下图👇),而且官网的 demo
肯定是不能直接用在生产环境下的, 不然… 等监控报警的时候,就有得难受了 哈哈
下面整理了一些配置 给小伙伴们参考下~ 😝
如下图
这两个分别是
路由最大连接数 : defaultMaxPerRoute
,默认值 2 ,表示对某个 ip
/ 路由 一次能处理的最大并发数 。例如,如果我去请求百度,则同一时刻,最多能处理两个请求,所以 别忘了修改它!🐷 ,不然你的连接池配多少连接都没用~
总连接数: maxTotal
, 默认值 20 , 这个表示总的连接数,即 连接的最大并发数是20
PoolingHttpClientConnectionManager 设置
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
poolingHttpClientConnectionManager.setMaxTotal(6);
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(1);
poolingHttpClientConnectionManager.setMaxPerRoute(new HttpRoute(new HttpHost("www.baidu.com")),4);
如上所示,还可以自定义某个 route
的最大值,效果如下~
DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection leased: [id: 41][route: {}->http://www.baidu.com:80][total available: 1; route allocated: 2 of 4; total allocated: 6 of 6]
其他参数 如 SocketConfig
,RequestConfig
等也要进行相应的配置,设置 等待数据的超时时间 和 请求超时时间 等,还有 重发策略 serviceUnavailStrategy
, Keep-Alive
策略 ConnectionKeepAliveStrategy
等
RequestConfig
设置
-
connectionRequestTimout
:从连接池获取连接超时 -
connetionTimeout
:连接服务器超时 -
socketTimeout
: 等待数据超时
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(1000)
.setConnectTimeout(1000)
.setSocketTimeout(1000).build();
ConnectionKeepAliveStrategy
(保活策略)设置
代码如下
ConnectionKeepAliveStrategy myStrategy = (response, context) -> {
// Honor 'keep-alive' header
HeaderElementIterator it = new BasicHeaderElementIterator(
response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext()) {
HeaderElement he = it.nextElement();
String param = he.getName();
String value = he.getValue();
if (value != null && param.equalsIgnoreCase("timeout")) {
try {
return Long.parseLong(value) * 1000;
} catch (NumberFormatException ignore) {
}
}
}
HttpHost target = (HttpHost) context.getAttribute(
HttpClientContext.HTTP_TARGET_HOST);
if ("www.baidu.com".equalsIgnoreCase(target.getHostName())) {
// Keep alive for 5 seconds only
return 5 * 1000;
} else {
// otherwise keep alive for 30 seconds
return 30 * 1000;
}
};
okhttp
就不展开啦,嘿嘿,这里的连接池使用场面也挺多的,比如我们接着要来讲的 RestTemplate
,还有这个 Feign
(这个就先记着啦 嘿嘿 有时间再补上)
现在来简单说下怎么在 RestTemplate
中使用这个连接池~ 🐷
RestTemplate
它提供了一个简单的 SimpleClientHttpRequestFactory
, 该类里面主要有 connetionTimeout
和 readTimeout
这两个超时设置,额 实在是太简单了… 大部分时候还是不能满足的,所以我们还是要选择其他的连接池呀~ !
可以看到上面中还有 OkHttp
,还有 Netty
等等,小伙伴们可以根据需要选择~ (๑•̀ㅂ•́)و✧
不过为啥 Netty
会标记为已过期了呢?
嘿嘿,这里下载了 Netty4ClientHttpRequestFactory
源码 ,可以看到 第一个红框里说,每次 http
请求的连接都会被关闭 。
这显然不能重用连接以及保持长连接了~ 😄
配置 HttpClient
我们也可以这样配置,就可以使用到这个 HttpClient
了 。
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
// 支持中文编码
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(Charset.forName("UTF-8")));
return restTemplate;
}
@Bean
public ClientHttpRequestFactory httpComponentsClientHttpRequestFactory() {
return new HttpComponentsClientHttpRequestFactory(httpClient());
}
@Bean
public HttpClient httpClient() {
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
poolingHttpClientConnectionManager.setMaxTotal(6);
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(1);
poolingHttpClientConnectionManager.setMaxPerRoute(new HttpRoute(new HttpHost("www.baidu.com")), 4);
ConnectionKeepAliveStrategy myStrategy = (response, context) -> {
// Honor 'keep-alive' header
HeaderElementIterator it = new BasicHeaderElementIterator(
response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext()) {
HeaderElement he = it.nextElement();
String param = he.getName();
String value = he.getValue();
if (value != null && param.equalsIgnoreCase("timeout")) {
try {
return Long.parseLong(value) * 1000;
} catch (NumberFormatException ignore) {
}
}
}
HttpHost target = (HttpHost) context.getAttribute(
HttpClientContext.HTTP_TARGET_HOST);
if ("www.baidu.com".equalsIgnoreCase(target.getHostName())) {
// Keep alive for 5 seconds only
return 5 * 1000;
} else {
// otherwise keep alive for 30 seconds
return 30 * 1000;
}
};
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(5000)
.setConnectTimeout(10000)
.setSocketTimeout(5000).build();
return HttpClients.custom()
.setConnectionManager(poolingHttpClientConnectionManager)
.setKeepAliveStrategy(myStrategy)
.setDefaultRequestConfig(requestConfig)
.build();
}
}
前往下一站,Redis 连接池
Redis 连接池
在 redis
的官网中 ,我们可以发现有下面这些客户端
这里我们主要介绍这个 lettuce
Jedis 和 Lettuce
好久以前,在花菜🥦
lettuce
还没有出现以前,Springboot
默认使用的是Jedis
为啥现在默认使用的是这个 lettuce
呢?
嘿嘿,翻译下作者的原话 😝
Jedis
是一个直连的Redis
客户端,在多线程环境下共享同一个Jedis
实例,这是线程不安全的。- 在多线程环境中使用
Jedis
的方法是使用连接池。每个使用Jedis
的并发线程在Jedis
交互期间获得自己的Jedis
实例。连接池是以每个Jedis
实例的物理连接为代价的,这增加了Redis
连接的数量。lettuce
是建立在netty
和连接实例(StatefulRedisConnection)之上,可以跨多个线程共享。因此,多线程应用程序可以使用单个连接而不考虑与Lettuce
交互的并发线程数。
配置
<!-- spring boot redis 缓存引入 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- lettuce pool 缓存连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
@Bean
public LettuceConnectionFactory lettuceConnectionFactory() {
GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
genericObjectPoolConfig.setMaxIdle(maxIdle);
genericObjectPoolConfig.setMinIdle(minIdle);
genericObjectPoolConfig.setMaxTotal(maxActive);
genericObjectPoolConfig.setMaxWaitMillis(maxWait);
genericObjectPoolConfig.setTimeBetweenEvictionRunsMillis(100);
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setDatabase(database);
redisStandaloneConfiguration.setHostName(host);
redisStandaloneConfiguration.setPort(port);
redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
.commandTimeout(Duration.ofMillis(timeout))
.shutdownTimeout(Duration.ofMillis(shutDownTimeout))
.poolConfig(genericObjectPoolConfig)
.build();
LettuceConnectionFactory factory = new LettuceConnectionFactory(redisStandaloneConfiguration, clientConfig);
factory.setShareNativeConnection(false);
return factory;
}
注意这里,如果想要连接池生效的话,必须设置配置这句话,不然默认只用一条连接的🐖
lettuceConnectionFactory.setShareNativeConnection(false);
特意去官网看了下,发现真是这样操作的 (⊙﹏⊙)
而且当你配置了最小连接数时,你会发现在 redis
中,查到的连接数是比你配置的多一个,额 目前还不知道是啥连接,先记录下 嘿嘿~
最后
这篇文章就分享到这里啦,至于 常量池 又要夹着 jvm
,还有字节码这一块来说,所以还是另外再写✍ 啦!
欢迎关注,交个朋友呀!! ( •̀ ω •́ )y
文章首发于公众号~
作者简介 :Java4ye , 你好呀!!😝
公众号: Java4ye 博主滴个人公众号~ ,嘿嘿 喜欢就支持下啦 😋
让我们开始这一场意外的相遇吧!~
欢迎留言!谢谢支持!ヾ(≧▽≦*)o
更多推荐
所有评论(0)