JCache CacheLoader:load与loadAll如何配合getAll实现批量回源?
几年前的面试大家喜欢问“缓存穿透怎么解决”“Redis雪崩怎么处理”这两年风向明显变了越来越多的团队开始抠规范本身比如今天要聊的这道题JCacheJSR-107中 loadAll 和 load 的用途是什么它们如何与 getAll 配合这道题问的是基础篇但真能答透的人不多。大多数人用过Caffeine、Redis却不一定看过 JCache 的CacheLoader接口更少有人会把getAll和loadAll的联动关系说清楚。这道题好在哪里它不考你背 API而是考你对“缓存回源”这件事有没有体系化的理解。load是单键回源loadAll是批量回源getAll则是批量读取的缓存入口。三者一串联就是一个完整的 read-through 模式。无论你是在准备高级 Java 面试还是要为团队设计一套缓存加载层把 JCache 这套机制吃透都能直接迁移到自己的项目中。这篇文章我会从 JSR-107 的设计逻辑讲起把load/loadAll的签名、行为差异、边界条件全部拆开再给出和getAll配合的完整代码示例最后整理一些我实际踩过的坑。内容偏实践适合正在准备面试的 Java 工程师也适合正打算引入 JCache 做缓存抽象层的架构师。1. JCache规范与CacheLoader的设计逻辑1.1 JSR-107到底统一了什么JSR-107 是 Java 官方的缓存规范定义了一套标准的缓存 API也就是我们常说的 JCache。它不是什么具体的缓存产品而是一层抽象业务代码通过javax.cache.Cache、javax.cache.CacheManager、javax.cache.configuration.Configuration这些标准接口操作缓存底层可以用本地内存、分布式内存甚至任何你喜欢的数据结构来存储。这套抽象最大的价值是让“缓存”成为可替换的基础设施。以前项目里用ConcurrentHashMap做缓存后来换了Caffeine就发现 API 不完全兼容再换又要改一遍业务代码。而 JCache 统一了接口之后缓存产品之间切换的成本只存在于初始化配置业务调用方几乎不用动。当然它也不是没有缺点为了兼容各种实现规范留了很多可选项导致某些方法在不同实现下的行为存在差异。CacheLoader就是典型的例子很多实现都支持但细节处理各有不同。JCache 定义了几个核心扩展点CacheLoader是其中最重要的一个。它负责解决一个关键问题当缓存里没有你要的数据时数据从哪来这个问题的答案就是 read-through 模式——缓存自己去找底层数据源而不是业务代码手动回源。1.2 CacheLoader在缓存模式中的角色read-through的落地点很多开发者第一次理解 read-through靠的是Caffeine的CacheLoader参数。其实 Caffeine 的这套设计思路就是借鉴了 JCache 规范的精神。在 read-through 模式下业务代码调cache.get(key)如果缓存命中就直接返回缓存值如果未命中缓存引擎会调用用户提供的加载函数去数据库、或者远程服务把数据查出来放进缓存再返回给调用方。整个过程对业务代码透明业务方只感觉“这个缓存好像什么都查得到”不需要在业务代码里写“先查缓存、没查到再查库、查到后写回缓存”这三行样板代码。这个样板逻辑被收敛到了CacheLoader实现里也就是我们今天要分析的核心对象。JCache 中的CacheLoader接口定义如下public interface CacheLoaderK, V { V load(K key) throws CacheLoaderException; MapK, V loadAll(Iterable? extends K keys) throws CacheLoaderException; }人们常困惑的地方就在这里既然已经有了get为什么还要getAll既然已经有了load为什么还要loadAll这其实对应了两种完全不同的使用场景单个键读取和批量键读取。缓存接口要满足这两种场景加载器也得提供对应的两个维度。下面我就把这两个方法的细节逐一拆开。2. 拆解CacheLoader的load与loadAll2.1 load(K key)单键回源的设计细节load(K key)是最简单的回源入口方法接收一个键返回对应的值。它解决的是单键未命中时的加载问题。比如在用户详情页请求某个用户 ID 对应的信息就可以用这个方法。这个方法有一个容易被忽略的细节返回值允许是null。规范里对null的处理比较微妙——返回null并不意味着加载失败而是表示“该键不存在”。举个例子如果你的用户表里没有 ID 为 99999 的用户load(99999)返回null就代表“查过了没有这个人”。此时 JCache 实现通常不会把这个null缓存起来下一次请求同样的键还是会再次触发load这也是一些面试官喜欢追问的“缓存穿透”问题的源头之一。还有一个常见的误解load只会在缓存未命中时被调用吗严格来说这取决于客户端调用的哪个 API。当你调用cache.get(key)且缓存不包含该键时JCache 实现会触发CacheLoader.load(key)来补漏。但如果你主动调用cache.load(key, ...)无论缓存里已有这个键还是永远不会读都可以强制触发加载。这一点在后续章节里我会展开。关于异常如果load内部抛了异常JCache 会把未受检异常包装成CacheLoaderException抛给调用方。实际开发中要注意数据库短暂不可用这类异常不应该被静默吞掉否则缓存层会把下游故障伪装成“键不存在”导致业务逻辑做出错误判断。2.2 loadAll(Iterable? extends K keys)批量回源的差异点loadAll(Iterable? extends K keys)接收一个键集合返回一个MapK, V。它的设计意图非常明确一次性为多个键加载数据减少与底层数据源之间的交互次数。这个方法和load的一个关键差异藏在其返回值里。loadAll返回的Map不需要完整覆盖传入的 keys。也就是说你传入 100 个键但底层数据源只存在 90 个你的实现完全可以只返回 90 条记录剩下 10 个“不存在”的键不放在返回 Map 里即可。JCache 规范允许这种部分返回实现方也不会因为缺了某个键而报错。正是因为这一点loadAll的实现可以做得非常高效对数据库执行一条SELECT ... WHERE id IN (...)查询把结果按 ID 组装成 Map缺失的 ID 自然就不在 Map 中省去了逐键判断“是否存在”的多余代码。还有一个细节值得注意loadAll的触发时机通常不会是一个单独的loadAll调用而是由getAll方法在检测到部分键未命中时触发的。这里就引出了最核心的衔接问题我会在下一章节详述。2.3 方法签名与返回值的关键约定把两个方法放在一起对比会更清晰对比维度load(K key)loadAll(Iterable? extends K keys)输入粒度单个键键集合返回类型V单个值或 nullMapK, V可部分返回典型触发场景cache.get(key) 未命中cache.getAll(keys) 部分未命中底层数据源交互1 次单键查询1 次批量查询null 值语义表示键不存在不包含在返回 Map 中即视为不存在异常处理抛 CacheLoaderException抛 CacheLoaderException从表格可以总结出实现时的两个铁律第一load返回 null 是合法的调用方要有处理“查无此键”的准备第二loadAll返回的 Map 不必包含全部请求键值缺失键天然代表不存在二者在语义上完全一致。我在项目里见过不少人把loadAll写成“遍历 keys 逐个调load再组装成 Map”功能上没错但完全没有发挥批量加载的性能优势。正确的姿势是在数据源层面尽量把多个键的查询合并成一条批量语句比如数据库里的IN查询、Redis 里的MGET、HTTP 服务里的批量接口。这也是loadAll存在的终极意义——性能。3. getAll与loadAll的联动机制3.1 getAll的语义先查缓存再补缺失在看 JCache 的getAll之前我们先看看它和Map的区别。JCache 接口里getAll(Set? extends K keys)返回的是MapK, V但它的返回内容并不保证包含所有请求键。只有缓存中“确实存在”的键才会出现在返回结果里不存在或者尚未加载的键不会被塞进返回值。这个语义和普通的Map.get完全不同。普通 Map 里你查一个键如果没有就是 null你无从分辨这个 null 是“没这个键”还是“存了 null”。JCache 的getAll则明确表示返回的 Map 里只包含命中的键值对。所以你可以从返回 Map 的keySet()大小推断出有多少键没有命中缓存。比如传入 100 个键缓存里只有 30 个getAll直接返回 30 条记录剩余 70 个键去哪了这就看实现是否配置了CacheLoader。配置了就会触发loadAll没配置缺失的 70 条就直接不返回由业务层自行决定怎么补。这个“先查缓存、再按需回源”的行为是理解本题目最核心的底层逻辑。3.2 getAll是如何触发loadAll的JCache 规范对getAll和loadAll的耦合方式说起来其实很直白getAll内部实现第一步先遍历传入的 keys从缓存存储中查出命中的键值对第二步把没有命中的键收集成一个缺失键集合第三步如果配置了CacheLoader就把这个缺失键集合交给loadAll去批量加载第四步把loadAll返回的数据写回缓存第五步一次性地将“原本命中的数据”和“新加载的数据”合并成一个完整的 Map 返回给调用方。关键点在于第三步loadAll接收到的不是调用getAll时的完整 keys而是去重之后、真正未命中的那部分键。这样的设计非常聪明它避免了重复加载已经缓存的数据也保证了对底层数据源的最小访问。举个例子缓存里已经有 A、B 两个键你调getAll([A, B, C, D])实现只会带着[C, D]去调loadAll而不是[A, B, C, D]。这种“按缺失键回源”的机制和Caffeine里的getAllPresent加loadAll组合非常相似如果你熟悉 Caffeine理解 JCache 的这套联动就毫无障碍。3.3 为什么不建议getAll逐个调load有些同学可能会想既然已经有load(K key)那getAll拿到缺失键列表后循环调load不就行了为什么还要单独设计一个loadAll原因只有一个性能以及封装性。性能层面的道理很直观假设缺失 50 个键逐个调load就意味着 50 次数据库往返。而使用loadAll合并成一条IN查询通常一次往返就能搞定。在分布式缓存场景下这种批量加载的优势更明显网络 RTT 的次数会从 N 次降为 1 次。封装性则体现在接口设计上。CacheLoader的实现者只关心“给我一批键我还你一批值”而不必关心缓存内部何时、为何需要加载。如果让getAll循环调load虽然也能完成任务但这个循环逻辑就会固化在缓存实现里无法让上层针对“批量查询”做专门优化。JCache 把loadAll单独抽出来本质上就是给实现者留出批量优化的空间让“批量”这件事从 API 层面得到表达。4. 从零实现一个CacheLoader并接入JCache4.1 选型怎么选JCache实现由于 JCache 只是规范实际使用前必须选一个实现。近年主流的选择包括完全实现 JCache 规范的开源缓存库以及部分支持该规范的内存缓存框架。我个人的建议是如果你的项目已经依赖了某个成熟的缓存框架优先看它是否支持javax.cache的CachingProvider如果是从零选型直接选择 API 完整、文档丰富、社区活跃的实现避免后续踩到兼容性深坑。初始化代码一般在Maven中增加依赖后用Caching.getCachingProvider()获取 Provider再通过CacheManager创建Cache。为了避免无谓的争论本文以最普通的 JCache 实现作为示例所有代码在标准 JSR-107 API 层面都是通用的。你在自己项目里替换成任何标准实现代码几乎不用改。4.2 完整代码示例模拟项目X的CacheLoader下面用一个虚拟的场景“模拟项目X”来演示。这个项目的业务是从一张订单表里读取订单详情我们希望在缓存未命中时自动按订单号批量回源数据库。先定义订单对象public class Order { private String orderId; private BigDecimal amount; private String status; // 构造器、getter、setter 省略 }实现CacheLoaderpublic class OrderCacheLoader implements CacheLoaderString, Order { private final OrderRepository orderRepository; public OrderCacheLoader(OrderRepository orderRepository) { this.orderRepository orderRepository; } Override public Order load(String orderId) { // 单键回源直接查一次数据库 return orderRepository.findById(orderId); } Override public MapString, Order loadAll(Iterable? extends String orderIds) { SetString ids new HashSet(); for (String id : orderIds) { ids.add(id); } // 批量回源一条 IN 查询搞定 ListOrder orders orderRepository.findByIds(ids); MapString, Order map new HashMap(); for (Order order : orders) { map.put(order.getOrderId(), order); } // 不存在的订单不会出现在 map 中 return map; } }然后初始化 JCache 缓存并配置CacheLoaderpublic class CacheInitializer { public CacheString, Order createOrderCache(OrderCacheLoader loader) { CachingProvider provider Caching.getCachingProvider(); CacheManager cacheManager provider.getCacheManager(); MutableConfigurationString, Order config new MutableConfiguration(); config.setTypes(String.class, Order.class); // 核心关键行让 CacheLoader 与 Cache 绑定 config.setCacheLoaderFactory(() - loader); // 是否开启 read-through若为 false则不会自动调 Loader config.setReadThrough(true); // 是否需要写入缓存如果业务需要可以直接打开 config.setWriteThrough(false); return cacheManager.createCache(orderCache, config); } }注意这里的两个开关setCacheLoaderFactory负责提供CacheLoader实例setReadThrough(true)则决定缓存未命中时是否自动调用该 Loader。很多人配了 Loader 却忘了打开 read-through导致代码写得很完整缓存却从不回源。4.3 配置与缓存初始化细节初始化完成后业务代码就可以用get和getAll来读数据了CacheString, Order orderCache initializer.createOrderCache(new OrderCacheLoader(repository)); // 单键读取未命中时自动调 load(1001) Order order orderCache.get(1001); // 批量读取未命中键自动调 loadAll(缺失键集合) SetString keys new HashSet(Arrays.asList(1001, 1002, 1003)); MapString, Order orders orderCache.getAll(keys);需要特别留意的是getAll返回的 Map 可能小于请求键集合。比如 1003 在数据库里根本不存在那么 orders 里只会有 1001 和 1002 两条记录。业务侧在偏乐观的场景下可能意识不到这一点因此拿到结果后最好比较一次orders.size()与keys.size()对缺失键单独做提示或兜底。另外JCache 的Cache接口里还有两个主动加载的方法load(K key, boolean replaceExistingValue, ...)和loadAll(SetK keys, boolean replaceExistingValue, ...)。它们和get、getAll不同属于“主动调用加载器”并不关心当前缓存里有没有数据。replaceExistingValue参数决定已经存在的缓存值是否要被覆盖。实际项目中我常用loadAll做缓存预热应用启动后直接把热点数据批量灌入缓存避免第一波请求全部穿透到数据库。5. 常见问题与踩坑实录5.1 loadAll返回空Map导致的问题有次在模拟项目X 的压测环境中我发现一个诡异现象getAll返回的数据经常少了一部分但数据库里明明有记录。排查到最后发现我在loadAll里写了一个 bug——把findByIds返回结果组装成 Map 时键用错了字段。更典型的坑是返回空 Map。如果你的loadAll在业务异常时直接返回Collections.emptyMap()那getAll会认为所有请求键在数据源里都不存在缺失键会被安静地丢弃。高层业务根本不知道底层发生了什么只会看到一个不完整的结果集。这种静默失败是缓存层最隐蔽的问题。我的建议是CacheLoader内部对异常要透明处理。数据库超时就要抛出异常让上层感知到加载失败只有“业务上确实查不到”时才返回空集合或 null。这两者绝不能混为一谈。5.2 键集合过大导致的批量回源压力getAll传入的 keys 数量是没有上限的如果调用方不小心传了几万个 IDloadAll就会带着几万个 ID 去做一次巨大的IN查询底层数据库大概率会被打爆。经验做法是给批量加载设置一个规模上限比如在getAll外层按 500 个键一组分批调用public MapString, Order getOrdersSafe(SetString keys) { MapString, Order result new HashMap(); ListString keyList new ArrayList(keys); for (int i 0; i keyList.size(); i 500) { int end Math.min(i 500, keyList.size()); SetString batch new HashSet(keyList.subList(i, end)); result.putAll(orderCache.getAll(batch)); } return result; }这里分批的粒度取决于实际数据库和数据源的能力并没有绝对标准。我个人习惯先设 500 做压测再根据平均响应时间调整。5.3 并发场景下getAll与loadAll的线程安全JCache 的Cache接口是线程安全的多个线程同时调用getAll不会破坏内部数据结构。但线程安全问题会出现在你自己的CacheLoader实现里。如果你的loadAll内部使用了状态变量或者底层数据源连接不是线程安全的就可能在并发触发时出问题。更隐蔽的是重复加载十个线程同时getAll缺失键理论上你希望只有一个线程去数据库加载其余线程等待结果但 JCache 规范并没有强制实现“单一回源”功能也就是防击穿机制各实现的行为差异很大。针对这一点我的建议是如果你的业务对缓存击穿特别敏感不要完全依赖 JCache 规范层面的保证可以在CacheLoader里自己做请求合并或者选择一个在实现上支持回源合并的缓存框架。我总是把规范当作“约定底线”而不是“性能保证”。下面把这个章节踩过的坑汇总一下方便大家速查现象可能原因解决思路getAll 返回结果缺失loadAll 返回的 Map 键对不上检查 loadAll 组装 Map 时使用的键数据源异常但上层无感知loadAll 内部吞掉异常并返回空 Map异常统一抛出只在“查无数据”时返回空数据库负载突然飙升getAll 传入超大 keys 集合调用方分批调用 getAll控制单批规模并发下数据库回源次数爆炸多个线程同时未命中同一批键在 CacheLoader 内做请求合并或选择支持合并的实现6. 从面试题到实战我的几点体会这道题看起来在考 JCache 的 API实际上考的是你能不能把“缓存未命中”这件事想清楚。我见过太多候选人能背出CacheLoader接口的方法名却说不清getAll内部触发loadAll时只传缺失键、以及loadAll允许部分返回这两条关键语义。这两个细节恰恰是 read-through 模式能否做到“高性能回源”的关键。拿我实际的经历来说最初做缓存封装时我也犯过循环调load的错误后来看了 JCache 规范才意识到loadAll的定位。当我把所有单键回源改成批量回源接口耗时直接从原本的 800 毫秒降到 120 毫秒原因很简单数据库的IN查询比 20 次单查快太多了。这个性能差距在分布式环境下会被进一步放大。面试答这道题你可以这样收尾“load和loadAll是 CacheLoader 提供给缓存的回源能力前者负责单键精确加载后者负责批量键的高效加载getAll会先查缓存再把缺失键聚合成集合交给loadAll最后合并结果返回。这个设计本质上是把 read-through 模式标准化让业务方无感命中和回源。” 如果能再补一句“loadAll返回的 Map 可以小于请求键集合表示那些键不存在”面试官通常会觉得你是真看过规范的。最后再分享一个小技巧如果你想看某个 JCache 实现具体怎么把getAll和loadAll串起来直接去翻它的源码搜索getAll和loadAll的调用链比读文档直观得多。缓存规范的设计哲学往往就藏在实现类的这几行代码里。

相关新闻

PCL点云圆柱体分割实战:RANSAC原理、参数调优与工业应用

PCL点云圆柱体分割实战:RANSAC原理、参数调优与工业应用

做点云处理这几年,我有个特别深的体会:几乎每个项目里需要找的几何元素,翻来覆去就那么几种——平面、球、圆柱。平面最简单,一个法线加一个距离就描述完;球也不难,中心加半径一共四个参数;唯独…

2026/10/13 21:30:25 阅读更多 →
PHP+UniApp开发宠物饲养交流系统实战

PHP+UniApp开发宠物饲养交流系统实战

1. 项目概述最近完成了一个宠物饲养交流系统的开发项目,采用PHP后端UniApp前端的混合开发模式。这个系统包含APP和小程序双端应用,主要解决宠物主人在饲养过程中遇到的交流、知识分享和日常管理需求。从技术选型到功能实现,整个项目走下来积累…

2026/10/13 21:30:25 阅读更多 →
litellm实战:统一大模型API与网关部署全解析

litellm实战:统一大模型API与网关部署全解析

1. 多家大模型API来回切换的痛苦,才是litellm真正的用武之地 过去一年,我先后在几个项目里接入了不同的大模型服务商。说实话,最让人头疼的不是模型效果本身,而是API的调用方式五花八门。有的用 messages 数组传对话历史&#x…

2026/10/13 21:30:25 阅读更多 →

最新新闻

Python超市管理系统源码实战:Flask+SQLite收银库存全流程

Python超市管理系统源码实战:Flask+SQLite收银库存全流程

简介:这是一份面向Python初学者与课程设计学习者的超市管理系统源码包,围绕员工管理、客户管理、登录验证与商品库存记录等日常运营场景展开,适合用来练习GUI界面搭建、文件持久化存储与模块化组织方式。压缩包共13个文件,约8KB&a…

2026/10/13 22:18:56 阅读更多 →
AI制图实测:10分钟生成架构图与流程图

AI制图实测:10分钟生成架构图与流程图

相信不少朋友都经历过这样的场景:刚画完一张系统架构图,产品经理又改了两版需求;刚理清一条业务主线,对接方又加了三个分支。画图这件事,听着很轻松,真正动手才发现,框要对齐、线要避开交叉、字…

2026/10/13 22:18:56 阅读更多 →
AI编程大模型免费活动的技术真相与工程实践指南

AI编程大模型免费活动的技术真相与工程实践指南

1. 项目概述:这不是“薅羊毛清单”,而是一份AI编程模型能力演进的实时观测日志“最新免费AI编程大模型活动汇总 2026年10月8日更新”——这个标题乍看像电商促销页,实则藏着当前AI工程落地最真实的脉搏。我从2023年起持续跟踪国内大模型在开发…

2026/10/13 22:18:56 阅读更多 →
PyTorch目标检测实战:小黄人检测从数据准备到模型训练全流程

PyTorch目标检测实战:小黄人检测从数据准备到模型训练全流程

最近用PyTorch做图像识别练习,选了个特别有画面感的入门任务——小黄人检测。目标检测这个名字听着有点唬人,但拆开其实就两件事:先把图片里的小黄人找出来,再用矩形框把它框住。上学那会儿做这类需求,第一反应是搞滑动…

2026/10/13 22:18:56 阅读更多 →
矩阵置零:原地算法与状态管理,LeetCode 73 题全解析

矩阵置零:原地算法与状态管理,LeetCode 73 题全解析

矩阵置零这个题,我第一次在刷题平台上看到时,内心是有点不屑的:两层循环,遇到 0 就改行改列,这不是有手就行?可当我真的原地写起来,才发现完全不是那么回事。题目本身很短:给定一个m…

2026/10/13 22:18:56 阅读更多 →
利用阿里云alidns实现DDNS动态解析:公网IP变化自动更新教程

利用阿里云alidns实现DDNS动态解析:公网IP变化自动更新教程

家里的宽带每隔一段时间公网IP就会变,尤其是不满运营商最长在线时长之后强制断线重拨的那种,老域名解析记录一直是旧IP,访问家里NAS或者是远程桌面全都得靠临时记IP来连,烦得不行。后来我把域名托管到了阿里云云解析,直…

2026/10/13 22:17:56 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 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/13 22:01:27 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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/12 18:11:17 阅读更多 →