Spring Boot整合Redis实战:序列化、缓存穿透与高并发踩坑复盘
写这篇文章之前先说个我最近帮一个同事排查问题的场景。他负责的接口加上了 Redis 缓存但并发一高数据库还是被冲垮了。我登上去一看缓存 key 是一串 \xAC\xED 开头的二进制乱码value 也是 JDK 序列化对象接口逻辑里没有空值缓存热点 key 过期的那一秒所有请求全部穿透到了数据库。这不怪他网上一搜“Spring Boot 整合 Redis”大多只告诉你怎么加依赖、怎么写配置类真正上线之后的隐蔽问题很少讲。所以我打算用一篇更完整的实战记录把 Spring Boot 整合 Redis 这件事从头到尾拆开讲先想清楚 Redis 在你项目里干什么再谈依赖、序列化、缓存三兄弟最后给一个能直接参考的商品详情缓存 Demo。这不是一篇只贴代码的教程更多是我在实际项目里踩过坑之后的复盘。无论你正准备第一次往 Spring Boot 项目里加 Redis还是已经加上了但线上偶发异常说不清楚原因这篇文章应该都能帮你少走几步弯路。1. 动手加依赖之前先搞清楚 Redis 在项目里到底承担什么角色1.1 缓存之外的高频角色很多人把 Redis 默认等同于“缓存”这没有错但会限制你的思路。我在项目里见过它被用来干这些事缓存读多写少、实时性要求不高的数据比如商品详情、配置项、用户画像摘要。这是最典型的使用方式。分布式锁多实例部署时同一个资源只能被一个节点处理。Redis 的 SETNX 加上过期时间可以做一个轻量级互斥锁。计数器/限流使用 INCR、INCRBY 统计浏览量、点击数再用 EXPIRE 做时间窗口限流实现成本比数据库计数低很多。会话或临时数据共享集群环境下把 Session 或一次性验证码放到 Redis多个服务实例都能读到。轻量级消息队列用 List 的阻塞读取实现简单的任务队列用 ZSet 做延迟队列。适合内部小规模异步任务但如果消息不能丢、需要事务性投递还是建议用专业的消息中间件。把这些角色想清楚再动手你才不会在第一版设计阶段就把方向走偏。比如有人非要把 Redis 当成主数据库存核心订单那后续的一致性和持久化问题会非常痛苦。1.2 不建议硬塞给 Redis 的数据Redis 虽然快但内存是稀缺资源并不是所有数据都适合往里面放。强事务、强一致的数据缓存本质是牺牲一致性换性能账务、库存扣减这类核心写操作不应该只依赖 Redis 来保证最终正确性。超大对象一个 value 存几 MB 的 JSON初期看着没毛病等量上来之后内存占用、网络带宽、序列化耗时都会成为瓶颈。长期不读的冷数据如果一批数据写入后一个月都不会有人访问占着内存只会挤压热点数据的空间。我在做缓存设计时会先给数据分类哪些可以容忍一段时间不一致哪些是绝对核心数据。缓存永远只是加速层不是数据本身的保险箱。1.3 Lettuce 还是 Jedis默认选择背后的逻辑Spring Boot 从 2.x 开始默认使用 Lettuce 作为 Redis 客户端。Lettuce 基于 Netty一个连接可以被多个线程共享天生支持异步和响应式而 Jedis 更老派每个实例对应一个物理连接使用方式直接但连接管理成本高。这也是 Spring Boot 默认选 Lettuce 的原因连接复用带来的资源节约。不过这里有个常见误解Lettuce 默认共享连接不代表你不需要连接池。连接池体现的是“获取连接”的排队和超时控制不是简单堆物理连接。至于具体怎么配下一节会展开。2. 依赖引入与自动配置Spring Boot 替你做了多少还留了哪些坑2.1 一个 starter 到底带来了什么在 pom.xml 里加上这两个依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency dependency groupIdorg.apache.commons/groupId artifactIdcommons-pool2/artifactId /dependency第二个依赖很容易被忽略。Spring Boot 的 Redis 自动配置只有检测到 commons-pool2 在 classpath 中才会真正创建连接池对象。也就是说你配置了lettuce.pool.max-active但没引入 commons-pool2这些参数基本不生效应用仍会工作在直连模式下。加上依赖后Spring Boot 的自动配置会做这些事根据RedisProperties创建连接工厂默认实现是LettuceConnectionFactory。创建RedisTemplateString, Object。创建StringRedisTemplate。这里有个很容易被忽略的点自动配置创建的RedisTemplate默认使用JdkSerializationRedisSerializer。它能跑通但你会遇到可读性极差、跨语言困难、类结构变更后反序列化失败等一系列问题。所以很多项目都会自定义一个 RedisTemplate这部分我会在专门章节里讲。2.2 连接参数配置与常见坑不同 Spring Boot 版本的配置前缀不一样这一点最容易翻车。Spring Boot 2.x 使用spring.redis.*Spring Boot 3.x 改成了spring.data.redis.*。假如你在 Boot 3.x 里写的是spring.redis.host启动不会报错但配置不会被读取Redis 会默认连到localhost:6379。我见过几次线上连错 Redis 的事故最后发现都是前缀写错。以 Spring Boot 3.x 为例一份比较稳妥的配置长这样spring: data: redis: host: 127.0.0.1 port: 6379 password: yourpass database: 0 timeout: 3s lettuce: pool: enabled: true max-active: 16 max-idle: 8 min-idle: 2 max-wait: 3s几个参数的含义我解释一下max-active连接池中最大的连接数。不是说一开始就创建 16 个连接而是使用高峰期最多能同时存在的连接数量。max-idle空闲状态下最多保留多少个连接。超过这个数量的空闲连接会被释放。min-idle池中最少保持多少个空闲连接。这个值不宜设太大Redis 服务端不会因为你开了 20 个空闲连接就更快。max-wait从池中获取连接的最大等待时间。如果池已经满了请求在这里排队超过时间就抛出异常而不是无限挂起。timeout在 Spring Data Redis 中既影响连接超时也影响读写超时。设置成 3 秒比较合理如果 Redis 异常导致所有业务请求卡住至少超时后能快速失败而不是让用户一直转圈。2.3 启动成功不等于 Redis 连通Spring Boot 启动时并不会主动连接 Redis只有第一次执行 Redis 操作时才真正建立连接。也就是说你看到一个应用正常启动Redis 配置可能是错的也可能 Redis 服务已经挂了。我习惯在服务里加一个健康检查接口用StringRedisTemplate写一个测试 key 再删掉RestController public class RedisHealthController { private final StringRedisTemplate stringRedisTemplate; public RedisHealthController(StringRedisTemplate stringRedisTemplate) { this.stringRedisTemplate stringRedisTemplate; } GetMapping(/redis/ping) public String ping() { stringRedisTemplate.opsForValue().set(health:test, ok, Duration.ofSeconds(5)); return stringRedisTemplate.opsForValue().get(health:test); } }这样至少能在部署后快速确认连接配置是通的。别把“应用能启动”当成“Redis 整合成功”。3. 序列化方案乱码、类型不匹配、和你看不懂的 \xAC\xED3.1 默认序列化器的乱码问题如果你什么都不配置直接用自动创建的RedisTemplate写入字符串然后用 redis-cli 看会看到这样的 key127.0.0.1:6379 keys * 1) \xac\xed\x00\x05t\x00\x03foo这个前缀正是 Java 序列化对象的魔数。JdkSerializationRedisSerializer会把 key 和 value 都用 Java 原生序列化处理对 Java 技术栈来说自洽但对运维不友好其他语言也无法直接解析一旦实体类结构变化历史数据反序列化直接失败。所以序列化方案一定要在写代码初期就定好不要等上了生产再来换。3.2 三种序列化方案怎么选我在项目里主要对比过三种方案StringRedisSerializerkey 和 value 都按 UTF-8 字符串处理适合纯字符串数据也能和 redis-cli 直接交互。Jackson2JsonRedisSerializerObject把对象序列化成 JSON但不保存类型信息反序列化时往往会得到一个LinkedHashMap要自己再转成目标 DTO比较麻烦。GenericJackson2JsonRedisSerializer序列化成 JSON同时会在 JSON 里写入class类型信息反序列化时能直接还原为原来的类型。从维护角度我更推荐这样组合key 用StringRedisSerializervalue 用GenericJackson2JsonRedisSerializer这样 redis-cli 能看到可读的 key缓存对象也能自动还原。但如果你的项目规约要求所有缓存都以字符串形式读写那么直接用StringRedisTemplate加手动 JSON 序列化也很省心。下面这张表是我实际选择时会参考的方案redis-cli 可读性跨语言友好度对象自动还原典型场景JdkSerializationRedisSerializer差差可以但依赖类结构不建议用于生产StringRedisSerializer 手动 JSON较好好需要手动转换通用缓存、接口返回对象GenericJackson2JsonRedisSerializer一般一般自动带 class追求省事的内部缓存3.3 一份可直接落地的 RedisConfig下面这个配置类是我在项目里常用的版本Configuration public class RedisConfig { Bean public RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) { RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(factory); StringRedisSerializer stringSerializer new StringRedisSerializer(); GenericJackson2JsonRedisSerializer jsonSerializer new GenericJackson2JsonRedisSerializer(); template.setKeySerializer(stringSerializer); template.setValueSerializer(jsonSerializer); template.setHashKeySerializer(stringSerializer); template.setHashValueSerializer(jsonSerializer); template.afterPropertiesSet(); return template; } }有几个细节必须提醒setHashKeySerializer和setHashValueSerializer很容易漏。如果漏掉Hash 结构的 key 仍然会走默认 JDK 序列化你在 redis-cli 里看到的 Hash 字段也是乱码。自定义 RedisTemplate 之后记得调用afterPropertiesSet()否则序列化器可能没有被正确初始化。GenericJackson2JsonRedisSerializer写入的 JSON 会带class字段查看的时候会看到类似[java.util.HashMap,{id:1}]的内容这是正常的别奇怪。如果你的线上环境已经用默认 JDK 序列化写入了一些旧数据切换序列化器后旧的 key 会读不出来。不要硬写兼容代码更建议在维护窗口期直接清理这些脏数据再用新序列化器重建缓存。清理大批量 key 时生产环境慎用KEYS *它会阻塞 Redis 服务。用 SCAN 增量遍历更安全redis-cli --scan --pattern product:* | xargs redis-cli del如果担心一次管道删除太多可以把 SCAN 的 count 调小分批处理。3.4 StringRedisTemplate 与自定义 RedisTemplate 的取舍如果你的缓存对象结构简单、字段不复杂我建议优先用StringRedisTemplate把对象手动转成 JSON 字符串后写入。理由很朴素手动 JSON 的数据在 redis-cli 里完全可读排查问题方便也不会出现class类型信息把数据撑大的问题。如果每个业务模块都要存各种对象手动 JSON 的代码会很啰嗦这时自定义 RedisTemplate 更划算。但代价是缓存内容里会夹杂类型信息对纯运维查看来说稍微有点噪音。我的习惯是把两种方式分开面向接口响应的缓存用 StringRedisTemplate 加手动 JSON内部临时状态用 RedisTemplate 自动序列化。这样兼顾可读性和开发效率。4. 缓存穿透、缓存击穿、缓存雪崩整合 Redis 之后绕不开的三个坎4.1 三个问题的差异先分清再动手这三个问题经常被混在一起说但它们的成因和应对方式完全不同。缓存穿透查询一个缓存和数据库里都不存在的 key。比如恶意请求随机生成大量不存在的商品 ID每次都直接打到数据库缓存形同虚设。缓存击穿某个热点 key 刚好过期大量并发请求同时发现缓存没了一起回源数据库数据库瞬间压力飙升。缓存雪崩大量 key 在几乎同一时刻过期。比如定时任务给所有商品设置了完全相同的过期时间零点一到全部失效数据库被一波流量打挂。穿透是针对“不存在的 key”击穿是针对“一个热点 key”雪崩是针对“一批 key”。看清区别之后方案会清晰很多。4.2 空值占位与布隆过滤器穿透问题的层层防线对付穿透成本最低的方案是缓存空值。逻辑不复杂查数据库发现结果为空时依然往 Redis 写一个空字符串并设置较短的过期时间比如 60 秒。String value redisTemplate.opsForValue().get(key); if (value null) { Product product productRepository.selectById(id); if (product null) { redisTemplate.opsForValue().set(key, , Duration.ofSeconds(60)); return null; } // 正常写入缓存 }注意空值缓存的时间不能太长否则数据真正写入后用户要等过期才能看到最新数据。通常 30 到 60 秒就够。如果业务对随机非法 ID 的防护要求更高再考虑布隆过滤器。布隆过滤器能高效判断“一定不存在”把不存在的 ID 挡在数据库查询之前。但它的误判率、可删除性、容量扩容都会增加系统复杂度小项目用空值缓存基本就能解决问题不必为了追求技术方案而盲目引组件。4.3 热点 key 过期瞬间用互斥锁重建缓存解决击穿问题我常用互斥锁方案。核心思想是当缓存失效时只允许一个请求去回源数据库其他请求等待这个请求重建缓存后再读取。public String getProductDetailWithLock(Long id) { String key product:detail: id; String cache redisTemplate.opsForValue().get(key); if (cache ! null) { return cache; } String lockKey lock:product: id; String requestId UUID.randomUUID().toString(); Boolean locked redisTemplate.opsForValue() .setIfAbsent(lockKey, requestId, Duration.ofSeconds(5)); if (Boolean.TRUE.equals(locked)) { try { // 双重检查可能在等待时其他线程已经重建了缓存 String again redisTemplate.opsForValue().get(key); if (again ! null) { return again; } Product product productRepository.selectById(id); String json product null ? : JSON.toJSONString(product); Duration expire product null ? Duration.ofSeconds(60) : Duration.ofMinutes(30); redisTemplate.opsForValue().set(key, json, expire); return json; } finally { // 用 requestId 防止误删其他线程的锁 if (requestId.equals(redisTemplate.opsForValue().get(lockKey))) { redisTemplate.delete(lockKey); } } } else { try { Thread.sleep(50); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } // 递归次数有限实际项目里建议改 while 循环控制重试次数 return getProductDetailWithLock(id); } }这里有几个关键点setIfAbsent(lockKey, requestId, Duration.ofSeconds(5))是 SET NX EX 的原子操作不会出现“加锁成功但过期时间没设置”的情况。释放锁之前要判断 value 是否等于自己的requestId。因为锁可能因业务执行时间过长而自动过期如果不判断旧请求可能删掉新请求已经持有的锁。锁的粒度要尽可能细。这里锁 key 里带了商品 ID只有同一个商品的请求才会互相等待不同商品不受影响。4.4 随机过期时间与多级缓存化解雪崩雪崩最常见的原因是过期时间设置得太“整齐”。解决办法很简单在基础过期时间上叠加一个随机值。long baseExpire Duration.ofMinutes(30).getSeconds(); long expire baseExpire ThreadLocalRandom.current().nextLong(0, 300); redisTemplate.opsForValue().set(key, json, Duration.ofSeconds(expire));这样同一批 key 的过期时间被均匀打散不会出现集体失效的波峰。缓存预热任务里也建议做同样的处理。更进一步的做法是引入本地缓存作为二级缓存比如应用内放一层 CaffeineRedis 兜底。当 Redis 中的热点 key 失效时本地缓存还能顶住一部分流量。这个方案效果明显但会引入缓存一致性、内存占用管理等问题属于团队需要权衡后再上的复杂方案。5. 完整落一个 Demo商品详情缓存5.1 需求与目录结构为了不纸上谈兵我基于一个最常见的“商品详情查询”场景给出一个最小可运行示例。接口要求是根据商品 ID 返回详情数据量较大查询成本较高适合做缓存。简化后的工程结构如下src/main/java ├── Application.java ├── controller │ └── ProductController.java ├── service │ └── ProductService.java ├── repository │ └── ProductRepository.java └── model └── Product.java为了聚焦 Redis 相关代码数据访问层用ProductRepository抽象实际项目中你可以用 JPA、MyBatis 或任何持久化框架实现。5.2 缓存读服务实现ProductService 的核心逻辑如下Service public class ProductService { public static final String PRODUCT_KEY_PREFIX product:detail:; public static final Duration EMPTY_CACHE_EXPIRE Duration.ofSeconds(60); public static final Duration NORMAL_CACHE_EXPIRE Duration.ofMinutes(30); private final StringRedisTemplate stringRedisTemplate; private final ProductRepository productRepository; public ProductService(StringRedisTemplate stringRedisTemplate, ProductRepository productRepository) { this.stringRedisTemplate stringRedisTemplate; this.productRepository productRepository; } public Product getProduct(Long id) { String key PRODUCT_KEY_PREFIX id; String json stringRedisTemplate.opsForValue().get(key); if (json ! null) { if (json.isEmpty()) { return null; } return JSON.parseObject(json, Product.class); } Product product productRepository.selectById(id); if (product null) { stringRedisTemplate.opsForValue().set(key, , EMPTY_CACHE_EXPIRE); return null; } stringRedisTemplate.opsForValue().set( key, JSON.toJSONString(product), NORMAL_CACHE_EXPIRE); return product; } }我特意用StringRedisTemplate配手动 JSON是因为商品详情这类接口返回的数据结构稳定手动 JSON 序列化出的字符串在 redis-cli 里一眼就能看懂。如果出现线上问题任何人都能直接GET product:detail:10001看内容排查成本很低。5.3 数据更新后的缓存一致性缓存不是只读的后端数据更新后缓存怎么办我常用的策略是“更新数据库后删除缓存”由下一次读请求去重建。Transactional public void updateProduct(Product product) { productRepository.updateById(product); stringRedisTemplate.delete(PRODUCT_KEY_PREFIX product.getId()); }更新数据库成功后删除缓存下一次查询会从数据库读取最新数据并重建缓存。这种方式适合缓存重建成本不高的场景。如果缓存重建特别耗时可以在事务提交后异步重建而不是直接删除。还要注意一个顺序问题尽量先更新数据库再删缓存。反过来会出现窗口期旧缓存被读到的风险虽然时间很短但核心场景下依然要避免。5.4 验证缓存是否真的生效很多人写完缓存逻辑只看接口响应快不快不够严谨。我习惯在数据访问层加一个查询计数器验证第二次请求到底有没有查库。Repository public class ProductRepository { private final AtomicLong queryCount new AtomicLong(); public Product selectById(Long id) { queryCount.incrementAndGet(); // 真实查询逻辑 return new Product(id, 测试商品, 100); } public long getQueryCount() { return queryCount.get(); } }然后连续两次调用接口观察第二次请求后queryCount是否没有增加。如果没增加说明缓存真正拦截了查询而不是只把代码写出来就算完事。另外生产环境排查缓存 key 时用 SCAN 而不是 KEYSredis-cli --scan --pattern product:detail:* | wc -l这样可以统计出当前线上到底有哪些商品缓存而不会让 Redis 进入阻塞状态。6. 从踩坑里挤出来的几条经验6.1 连接池大小别拍脑袋决定很多人看到并发高就无脑调大 max-active结果 Redis 服务端连接数暴涨性能反而下降。Lettuce 的连接是支持线程共享的不像 Jedis 那样每个请求都需要独占连接所以连接池更多是在控制“获取连接”的排队行为而不是为每个线程准备一个物理连接。我通常从max-active16、max-idle8、min-idle2起步然后压测观察 Redis 连接数、CPU 和业务接口响应时间再调整。如果请求超过 1000 QPS 就调大到 64反而要怀疑代码里是不是有连接未释放或者其他资源问题。6.2 事务和 Pipeline 的隐蔽坑Transactional注解只能管理 Spring 管理的事务默认条件下 Redis 操作并不会自动加入到这个事务里。你想让 RedisTemplate 配合 Spring 事务必须显式开启redisTemplate.setEnableTransactionSupport(true);开启之后事务期间的操作会被暂存事务提交时再统一发送到 Redis。但要注意这意味着 Redis 命令不会立即执行如果事务很大内存中暂存的命令也会积压。Pipeline 也是一个容易出问题的地方。批量写入几千个 key 时Pipeline 确实快但如果你在 Pipeline 里混入了单个执行也会出错的命令异常可能不会立刻抛出来而是在 flush 阶段才体现。我一般建议只在纯批量写入场景用 Pipeline并且用 try-finally 确保连接资源被释放。6.3 大 Key 与删除方式我在一个订单系统里遇到过价值 2MB 的 JSON 缓存单个 key 占用过大之后内存和带宽压力都非常明显。后来把数据按维度拆成了多个 key问题才缓解。如果你发现某个 key 确实很难避免变大至少要做到两点给缓存设置合理的过期时间避免长期占内存。删除大 key 时用 unlink 代替 delRedis 4.0 开始支持异步删除不会阻塞主线程。Spring Data Redis 高版本中可以直接使用unlink方法或者通过底层的connection执行。删除单个大 key 的性能差异在数据上到几百 MB 时非常明显。6.4 淘汰策略noeviction 是隐藏事故源如果 Redis 没有配置内存上限系统内存耗尽时进程可能被 OOM Killer 干掉。如果配置了 maxmemory但没有配置淘汰策略默认noeviction会让写入直接报错。我习惯在 redis.conf 里这样设置maxmemory 512mb maxmemory-policy allkeys-lruallkeys-lru表示内存满了之后按 LRU 策略淘汰任意 key。如果你的业务有大量必须保留的 key可以用volatile-lru但前提是所有 key 都设置了过期时间。坦白说在缓存场景下我更倾向于allkeys-lru因为总有粗心的人忘记给 key 设置过期时间这时至少还有兜底策略不会让整个 Redis 拒绝写入。6.5 一点个人习惯最后分享一个我自己的实践习惯每个新项目引入 Redis 时我都会先封装一个简单的缓存工具类统一管理 key 前缀、过期时间、空值占位和 JSON 序列化而不是让各个业务直接乱用 RedisTemplate。这样做的最大好处不是代码优雅而是线上出问题时你知道所有缓存行为都遵循同一套规则排查起来会省非常多的时间。缓存这个东西写起来容易压测和运维才是真正见功夫的地方。希望这篇文章能帮你把整合 Spring Boot 和 Redis 时那些“看不见的坑”提前填平。

相关新闻

AI辅助教材编写如何降低查重率?从初稿到改稿的完整实践方法

AI辅助教材编写如何降低查重率?从初稿到改稿的完整实践方法

写教材这事,听起来是专家干的活,但这两年,越来越多的老师、培训讲师、课程开发者开始用AI辅助编写教材和讲义。我的感受是,AI写初稿是真快,但交出去的稿子质量和查重率往往让人头大。初稿太像“翻译腔”或“论文摘要合…

2026/10/18 2:38:02 阅读更多 →
游戏开发必知的10大测试术语揭秘

游戏开发必知的10大测试术语揭秘

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 2:38:02 阅读更多 →
用游戏讲透环境变量的神奇作用

用游戏讲透环境变量的神奇作用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 2:38:02 阅读更多 →

最新新闻

海康威视C++ SDK工程骨架:登录/取流/云台控制全链路实践

海康威视C++ SDK工程骨架:登录/取流/云台控制全链路实践

简介:本资源是海康威视HCNetSDK V5.1.1.4(2015年4月20日发布的64位Windows中文版)完整C开发包,面向安防监控领域初/中级C开发者,解决视频设备接入、实时预览、云台控制、录像回放及报警处理等核心二次开发需求。压缩包…

2026/10/18 3:22:16 阅读更多 →
SpringBoot集成RabbitMQ:消息队列解耦削峰与可靠投递实战

SpringBoot集成RabbitMQ:消息队列解耦削峰与可靠投递实战

我在做某个电商项目时遇到过一件特别头疼的事:用户下单后,系统需要同步发短信、发邮件、更新库存、通知物流系统,这一串调用下来接口要 2 秒多。赶上大促流量一上来,数据库连接被占满,整个下单链路直接雪崩。后来我把订…

2026/10/18 3:22:16 阅读更多 →
雷达导引头系统建模仿真:从需求到验收的完整方案

雷达导引头系统建模仿真:从需求到验收的完整方案

简介:这份雷达导引头系统建模仿真资源面向电子信息、雷达工程及信号处理方向的本科生与研究生,尤其适合正在做毕业设计或课题实践的学习者。内容围绕雷达导引头的物理特性、工作原理与典型应用场景展开,通过数学建模与计算机仿真预测系统性能…

2026/10/18 3:22:16 阅读更多 →
Redis分布式集群入门:核心数据结构、持久化与高可用基础

Redis分布式集群入门:核心数据结构、持久化与高可用基础

1. 从单机缓存到分布式集群:Redis到底解决了什么问题很多人第一次接触Redis,是因为项目里某个接口慢得让人抓狂——数据库查询要几百毫秒,并发一上来直接打满连接池。这时候老同事通常会甩过来一句"加个Redis缓存吧",然…

2026/10/18 3:22:16 阅读更多 →
三阶连续时间Delta-Sigma ADC的Matlab仿真与噪声整形设计

三阶连续时间Delta-Sigma ADC的Matlab仿真与噪声整形设计

简介:这是一份面向模拟集成电路与信号处理学习者的3阶连续时间Delta-Sigma ADC Matlab仿真代码,适合具备一定ADC理论基础、希望深入理解CTSDM架构与性能评估的工程师或研究生。资源包共10个文件,包含3个m脚本、3篇pdf参考论文、1个mdl Simuli…

2026/10/18 3:22:16 阅读更多 →
Java游戏矩形碰撞检测实战:从原理到工业级优化

Java游戏矩形碰撞检测实战:从原理到工业级优化

1. 这不是数学题,是游戏里“撞上就该有反应”的真实逻辑“Java游戏中的矩形碰撞检测”——这八个字背后,藏着无数新手在写第一个贪吃蛇、推箱子或横版跳跃游戏时卡住的三小时。它看起来像小学数学里的“两个长方形有没有重叠”,但实际运行中&…

2026/10/18 3:21:15 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →