lettuce 默认情况下连接池参数不生效,源码分析
先说结论:
1.LettuceConnectionFactory 属性 shareNativeConnection 默认为true,要想连接池生效,该参数设置为false; 2.使用redisTemplate模版封装的pipeline没有意义,autoFlashCommands 默认为true;
spring2.0开始默认使用lettuce,lettuce和jedis一样支持使用连接池;这里不对比两款客户端的性能差异,只针对使用lettuce客户端执行命令获取连接的源码分析其逻辑;
版本说明:
spring-date-redis:2.3.9.RELEASE;
lettuce-core:5.3.7.RELEASE;
以单机版本reids说明;即:RedisStandaloneConfiguration,集群也是同样方法
以 stringRedisTemplate.opsForValue().get(key) 示例追踪说明;
点击进入get方法:
public V get(Object key) {return this.execute(new AbstractOperations<K, V>.ValueDeserializingRedisCallback(key) {protected byte[] inRedis(byte[] rawKey, RedisConnection connection) {return connection.get(rawKey);}}, true);
}
接着进入execute方法:
@Nullable
<T> T execute(RedisCallback<T> callback, boolean exposeConnection) {return this.template.execute(callback, exposeConnection);
}
接着进入:org.springframework.data.redis.core.RedisTemplate#execute(org.springframework.data.redis.core.RedisCallback<T>, boolean, boolean);
@Nullable
public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {Assert.isTrue(this.initialized, "template not initialized; call afterPropertiesSet() before using it");Assert.notNull(action, "Callback object must not be null");RedisConnectionFactory factory = this.getRequiredConnectionFactory();RedisConnection conn = null;Object var11;try {if (this.enableTransactionSupport) {conn = RedisConnectionUtils.bindConnection(factory, this.enableTransactionSupport);} else {conn = RedisConnectionUtils.getConnection(factory);}boolean existingConnection = TransactionSynchronizationManager.hasResource(factory);RedisConnection connToUse = this.preProcessConnection(conn, existingConnection);boolean pipelineStatus = connToUse.isPipelined();if (pipeline && !pipelineStatus) {connToUse.openPipeline();}RedisConnection connToExpose = exposeConnection ? connToUse : this.createRedisConnectionProxy(connToUse);T result = action.doInRedis(connToExpose);if (pipeline && !pipelineStatus) {connToUse.closePipeline();}var11 = this.postProcessResult(result, connToUse, existingConnection);} finally {RedisConnectionUtils.releaseConnection(conn, factory, this.enableTransactionSupport);}return var11;
}
到这里后进入获取连接的入口:conn = RedisConnectionUtils.getConnection(factory);
点进去到:org.springframework.data.redis.core.RedisConnectionUtils#doGetConnection
public static RedisConnection doGetConnection(RedisConnectionFactory factory, boolean allowCreate, boolean bind, boolean transactionSupport) {Assert.notNull(factory, "No RedisConnectionFactory specified");RedisConnectionUtils.RedisConnectionHolder connHolder = (RedisConnectionUtils.RedisConnectionHolder)TransactionSynchronizationManager.getResource(factory);if (connHolder != null) {if (transactionSupport) {potentiallyRegisterTransactionSynchronisation(connHolder, factory);}return connHolder.getConnection();} else if (!allowCreate) {throw new IllegalArgumentException("No connection found and allowCreate = false");} else {if (log.isDebugEnabled()) {log.debug("Opening RedisConnection");}RedisConnection conn = factory.getConnection();if (bind) {RedisConnection connectionToBind = conn;if (transactionSupport && isActualNonReadonlyTransactionActive()) {connectionToBind = createConnectionProxy(conn, factory);}connHolder = new RedisConnectionUtils.RedisConnectionHolder(connectionToBind);TransactionSynchronizationManager.bindResource(factory, connHolder);if (transactionSupport) {potentiallyRegisterTransactionSynchronisation(connHolder, factory);}return connHolder.getConnection();} else {return conn;}}
}
忽略事务相关逻辑,进入:factory.getConnection();
public RedisConnection getConnection() {if (this.isClusterAware()) {return this.getClusterConnection();} else {LettuceConnection connection = this.doCreateLettuceConnection(this.getSharedConnection(), this.connectionProvider, this.getTimeout(), this.getDatabase());connection.setConvertPipelineAndTxResults(this.convertPipelineAndTxResults);return connection;}
}
先看:this.getSharedConnection();核心逻辑this.shareNativeConnection 标志位判断,默认为true;
org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory#getSharedConnection
@Nullableprotected StatefulRedisConnection<byte[], byte[]> getSharedConnection() {return this.shareNativeConnection ? (StatefulRedisConnection)this.getOrCreateSharedConnection().getConnection() : null;}
在进入核心方法:this.getOrCreateSharedConnection().getConnection();this.connection同步只会创建一次
private LettuceConnectionFactory.SharedConnection<byte[]> getOrCreateSharedConnection() {synchronized(this.connectionMonitor) {if (this.connection == null) {this.connection = new LettuceConnectionFactory.SharedConnection(this.connectionProvider);}return this.connection;}}
@NullableStatefulConnection<E, E> getConnection() {synchronized(this.connectionMonitor) {if (this.connection == null) {this.connection = this.getNativeConnection();}if (LettuceConnectionFactory.this.getValidateConnection()) {this.validateConnection();}return this.connection;}}
private StatefulConnection<E, E> getNativeConnection() {return this.connectionProvider.getConnection(StatefulConnection.class);}
public <T extends StatefulConnection<?, ?>> T getConnection(Class<T> connectionType) {GenericObjectPool pool = (GenericObjectPool)this.pools.computeIfAbsent(connectionType, (poolType) -> {return ConnectionPoolSupport.createGenericObjectPool(() -> {return this.connectionProvider.getConnection(connectionType);}, this.poolConfig, false);});try {StatefulConnection<?, ?> connection = (StatefulConnection)pool.borrowObject();this.poolRef.put(connection, pool);return (StatefulConnection)connectionType.cast(connection);} catch (Exception var4) {throw new PoolException("Could not get a resource from the pool", var4);}}
这里只会从pool里获取一个链接,后面不会再获取
进入:this.doCreateLettuceConnection(this.getSharedConnection(), this.connectionProvider, this.getTimeout(), this.getDatabase())
protected LettuceConnection doCreateLettuceConnection(@Nullable StatefulRedisConnection<byte[], byte[]> sharedConnection, LettuceConnectionProvider connectionProvider, long timeout, int database) {LettuceConnection connection = new LettuceConnection(sharedConnection, connectionProvider, timeout, database);connection.setPipeliningFlushPolicy(this.pipeliningFlushPolicy);return connection;}
其中 LettuceConnection connection = new LettuceConnection(sharedConnection, connectionProvider, timeout, database); 每次会把同一个连接赋值给asyncSharedConn
LettuceConnection(@Nullable StatefulConnection<byte[], byte[]> sharedConnection, LettuceConnectionProvider connectionProvider, long timeout, int defaultDbIndex) {this.isClosed = false;this.isMulti = false;this.isPipelined = false;this.txResults = new LinkedList();this.convertPipelineAndTxResults = true;this.pipeliningFlushPolicy = LettuceConnection.PipeliningFlushPolicy.flushEachCommand();Assert.notNull(connectionProvider, "LettuceConnectionProvider must not be null.");this.asyncSharedConn = sharedConnection;this.connectionProvider = connectionProvider;this.timeout = timeout;this.defaultDbIndex = defaultDbIndex;this.dbIndex = this.defaultDbIndex;}
回到命令执行方法:org.springframework.data.redis.core.RedisTemplate#execute(org.springframework.data.redis.core.RedisCallback<T>, boolean, boolean)
来到:T result = action.doInRedis(connToExpose);
会进到:org.springframework.data.redis.connection.DefaultStringRedisConnection#get(byte[])

this.delegate.get(key)会进入到:org.springframework.data.redis.connection.lettuce.LettuceStringCommands#get

进入this.getConnection;
org.springframework.data.redis.connection.lettuce.LettuceConnection#getConnection()

到这里就用到了之前在 LettuceConnection connection = new LettuceConnection(sharedConnection, connectionProvider, timeout, database); 方法里赋值给asyncSharedConn 的对象;
如果为null即上面shareNativeConnection为false,会走 this.getDedicatedConnection() :org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider#getConnection 从连接池里获取链接

获取到链接之后会进入:io.lettuce.core.AbstractRedisAsyncCommands#dispatch(io.lettuce.core.protocol.RedisCommand<K,V,T>)
至此已经能够看出shareNativeConnection参数true和false的区别
单独看下pipeline的执行方法,
首先pipeline获取链接的方法为:org.springframework.data.redis.connection.lettuce.LettuceConnection#getOrCreateDedicatedConnection
private StatefulConnection<byte[], byte[]> getOrCreateDedicatedConnection() {if (this.asyncDedicatedConn == null) {this.asyncDedicatedConn = this.doGetAsyncDedicatedConnection();}return this.asyncDedicatedConn;}
赋值给了asyncDedicatedConn;后面不在赋值;跟简单命令set/get使用的不是相同的链接;但是获取链接的方法少了synchronized同步关键字;猜想作者觉得pipeline使用场景并发不大不用同步;
然后找到pipeline命令执行方法,可以在此处断点验证,pipeline第一条命令执行完redis是否已经有值了:io.lettuce.core.protocol.DefaultEndpoint#write(io.lettuce.core.protocol.RedisCommand<K,V,T>)

这个属性autoFlushCommands 在对象创建时赋值,目前没有提供动态配置:
public DefaultEndpoint(ClientOptions clientOptions, ClientResources clientResources) {this.endpointId = ENDPOINT_COUNTER.incrementAndGet();this.sharedLock = new SharedLock();this.debugEnabled = logger.isDebugEnabled();this.closeFuture = new CompletableFuture();this.autoFlushCommands = true;this.inActivation = false;this.queueSize = 0;this.status = 0;LettuceAssert.notNull(clientOptions, "ClientOptions must not be null");LettuceAssert.notNull(clientOptions, "ClientResources must not be null");this.clientOptions = clientOptions;this.clientResources = clientResources;this.reliability = clientOptions.isAutoReconnect() ? DefaultEndpoint.Reliability.AT_LEAST_ONCE : DefaultEndpoint.Reliability.AT_MOST_ONCE;this.disconnectedBuffer = LettuceFactories.newConcurrentQueue(clientOptions.getRequestQueueSize());this.commandBuffer = LettuceFactories.newConcurrentQueue(clientOptions.getRequestQueueSize());this.boundedQueues = clientOptions.getRequestQueueSize() != 2147483647;this.rejectCommandsWhileDisconnected = isRejectCommand(clientOptions);}
相关文章:
lettuce 默认情况下连接池参数不生效,源码分析
先说结论: 1.LettuceConnectionFactory 属性 shareNativeConnection 默认为true,要想连接池生效,该参数设置为false; 2.使用redisTemplate模版封装的pipeline没有意义,autoFlashCommands 默认为true;spring2.0开始默认使用lettuc…...
《宇宙机器人》提示错误弹窗“找不到d3dx9_43.dll”是什么原因?“d3dx9_43.dll缺失”怎么解决?
电脑游戏运行时常见问题解析:《宇宙机器人》提示“找不到d3dx9_43.dll”的解决之道 TGA2024落幕,年度最佳游戏——《宇宙机器人》,作为一名在软件开发领域深耕多年的从业者,我深知电脑游戏在运行过程中可能会遇到的各种挑战&…...
应用于项目的 C++单例基类的设计、实现与应用
文章目录 应用于项目的 C单例基类的设计、实现与应用一、引言二、单例基类的设计2.1 线程安全的单例基类2.2 局部静态变量的单例基类 三、单例基类的实现3.1 配置管理单例类 四、单例基类的应用4.1 多线程环境下的配置管理 五、深入探讨5.1 单例的线程安全问题5.2 单例的延迟初…...
Mongodb 启用认证
MongoDB 启用认证的完整指南 启用 MongoDB 的认证功能需要按照以下步骤进行设置: 检查 MongoDB 配置文件 在 MongoDB 配置文件中(通常为 mongod.conf),需要启用认证功能。 修改配置文件 打开 mongod.conf 文件,找…...
QT:vlc出错处理及重新播放
这个问题一直想解决,昨天认真研究了一下。 要点 视频用的Widget不能重复使用,每次出错后,都要新建。 回调函数的处理。 代码1 关键在于libvlc_event_attach void VideoWidget::play() {libvlc_media_t* media;if (strstr(video_path, &…...
密钥管理系统在数据安全解决方案中的重要性
密钥管理系统在数据安全解决方案中占据着举足轻重的地位,其重要性体现在以下几个方面: 一、保障数据机密性 密钥管理系统通过生成、存储和管理加密密钥,确保了数据的机密性。这些密钥用于加密和解密数据,只有授权用户才能访问和…...
Docker的容器编排
目录 1. 什么是容器编排(Docker Compose)2. 容器编排的功能3. 容器编排文件(docker-compose.yml)的介绍3.1 文件语法版本3.2 文件基本结构及常见指令 4. Docker Compose命令详解4.1 Docker Compose命令清单4.2 命令格式和常见选项…...
Java Web项目部署教程简单实用
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默, 忍不住分享一下给大家。点击跳转到网站 学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……) 2、学会Oracle数据库入门到入土用法(创作中……) 3、手把…...
推送本地仓库到远程git仓库
目录 推送本地仓库到远程git仓库1.1修改本地仓库用户名1.2 push 命令1.3远程分支查看 推送本地仓库到远程git仓库 删除之前的仓库中的所有内容,从新建库,同时创建一个 A.txt 文件 清空原有的远程仓库内容,重新创建一个新的仓库,…...
线性池学习
一、什么是进程?什么是线程? 1. 进程的定义 从操作系统的角度解释: 进程是操作系统分配资源和调度执行的基本单位。每个进程都是操作系统中一个独立的实体,拥有自己的内存空间、文件描述符、代码、数据等资源。进程是程序在执行…...
微积分复习笔记 Calculus Volume 2 - 4.3 Separable Equations
4.3 Separable Equations - Calculus Volume 2 | OpenStax...
前端项目部署方法
ngnix服务器部署 下载nignx,我下的是windows版本的 下载链接:[https://nginx.org/en/download.html](https://nginx.org/en/download.html) 解压文件 如果原本的80端口号被占用了,可以改为其他的端口号 可以点击nginx.exe文件启动nginx,它可能…...
Docker创建一个mongodb实例,并用springboot连接 mongodb进行读写文件
一、通过Docker 进行运行一个 mongodb实例 1、拉取镜像 docker pull mongo:5.0.5 2、创建 mongodb容器实例 docker run -d --name mongodb2 \-e MONGO_INITDB_ROOT_USERNAMEsalaryMongo \-e MONGO_INITDB_ROOT_PASSWORD123456 \-p 27017:27017 \mongo:5.0.5 3、进入容器&am…...
Android app反编译 攻与防
大概是2020年的时候,有一次,我们的竞争同行有另外一家公司要用我们的安卓软件app,拉了个群,告知他用一个软件多少钱,然后在群里发了一个我打包的apk包。结果就没有下文了。又过了一个月。我同事在那个要买我们apk的人的朋友圈&…...
ElasticSearch 简介
一、什么是 ElastcSearch? ElasticSearch 是基于 Lucene 的 Restful 的分布式实时全文搜索引擎。 1.1 ElasticSearh 的基本术语概念 index 索引 索引类似与 mysql 中的数据库,ES 中的索引是存储数据的地方,包含了一堆有相似结构的文档数据…...
Kerberos实验
kdc:192.168.72.163 客户端(机器账户win10):192.168.72.159 用户:administrator 抓包:开机登录win10,使用administrator域用户凭据登录。 生成 Kerberos 解密文件 抓取 krbtgt 用户和 win1…...
Android之RecyclerView显示数据列表和网格
一、RecyclerView的优势 RecyclerView 的最大优势在于,它对大型列表来说非常高效: 默认情况下,RecyclerView 仅会处理或绘制当前显示在屏幕上的项。例如,如果您的列表包含一千个元素,但只有 10 个元素可见࿰…...
docker mysql挂载
在提供的 docker run 命令中,已经挂载了三个卷到 MySQL 容器中:日志目录、数据目录和配置目录。然而,还没有挂载一个包含 cube_admin.sql 文件的目录。要将 SQL 文件放入容器中并在 MySQL 中执行它,可以按照以下步骤操作ÿ…...
顺序表-递增有序表合并
两个递增有序表合并操作 题目: 将两个递增有序的顺序表 A 和 B 合并成一个新的递增有序顺序表 C。 思路: 使用三个索引 i, j, k 分别遍历顺序表 A, B 和合并后的顺序表 C。比较 A 和 B 当前索引指向的元素,将较小的元素放入 C 中…...
【Qt】qt安装
在工作一年之后,还是想做一个Qt的教程,遥想研一刚刚接触Qt,从0到1学习,没有什么参考书籍,网上的资料也不多,幸好Qt官方文档写得好,加上自己肯研究,才堪堪入门。 现在我想自己写一个…...
为什么头部AI团队已弃用Triton+ONNX Runtime?Cuvil架构设计图暴露Python推理第三条路!
第一章:Cuvil编译器在Python AI推理中的应用全景概览Cuvil编译器是一款面向AI工作负载的轻量级领域专用编译器,专为优化Python生态中基于PyTorch、ONNX及自定义计算图的推理流程而设计。它不替代传统Python解释器,而是通过源码到IR࿰…...
无人水下航行器(UUV)与无人航空系统(UAS)时空会合关键技术研究附Matlab代码
✅作者简介:热爱科研的Matlab仿真开发者,擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室🍊个人信条:格物致知,完整Matlab代码及仿真咨询…...
花小钱办大事!微调Nova Lite,实现Pro级视觉检测效果
本文介绍了在Amazon Bedrock上对Amazon Nova Lite 1.0进行微调的两个实际应用案例,展示了在专业计算机视觉任务中,如何在保持成本效益的同时显著提升性能。通过对航拍视角检测和低光照监控场景的系统性评估,本例以最小的训练成本实现了增强的…...
极客玩法:OpenClaw+Qwen3-14B控制智能家居实战
极客玩法:OpenClawQwen3-14B控制智能家居实战 1. 为什么选择OpenClaw控制智能家居? 去年装修新房时,我给自己定了个小目标:所有智能设备必须能通过自然语言控制。市面上的语音助手总让我觉得"差点意思"——要么响应慢…...
xgboost 训练一个 限制各个因素相关性的模型
XGB/LGB调参秘籍,解锁新高度! 在机器学习特别是风控模型的应用中,XGBoost和LightGBM因其出色的性能而备受青睐。然而,要充分发挥这些模型的潜力,合理的参数调校至关重要。今天,我们就来深入探讨XGBoost/Lig…...
探索XPopup:一款强大的Android弹窗库,让UI交互更灵动
探索XPopup:一款强大的Android弹窗库,让UI交互更灵动 【免费下载链接】XPopup 🔥XPopup2.0版本重磅来袭,2倍以上性能提升,带来可观的动画性能优化和交互细节的提升!!!功能强大&#…...
SSM+JSP动漫网站源码+论文
代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹 分享万套开题报告任务书答辩PPT模板 作者完整代码目录供你选择: 《SpringBoot网站项目》1800套 《SSM网站项目》1500套 《小程序项目》1600套 《APP项目》1500套 《Python网站项目》…...
为什么99%的Python团队还没用上AOT?2026年官方方案的3大硬伤与2个绕过技巧(含patch diff与CI集成脚本)
第一章:Python 原生 AOT 编译方案 2026 概览与演进脉络Python 长期以来以解释执行和 JIT 辅助(如 PyPy)为主流运行范式,而原生 Ahead-of-Time(AOT)编译在 2026 年迎来实质性突破:CPython 官方正…...
vue3 diff算法中的-双端 Diff + 最长递增子序列 讲解
一句话总结 Vue3 Diff 双端比较(快速复用) 最长递增子序列(最小移动 DOM) 目的:在乱序节点中,只移动最少 DOM,实现最高效更新。1. 先搞懂:Vue3 对比 Vue2 差在哪? Vue2…...
【应答器】基于matlab应答器特殊区段信息包报文编码仿真【含Matlab源码 15258期】
💥💥💥💥💥💥💞💞💞💞💞💞💞💞欢迎来到海神之光博客之家💞💞💞Ὁ…...
