新闻详情

新闻详情

首页 / 资讯中心 / 详情

PageHelper与LIMIT分页:原理、集成、坑点与深分页优化实践

发布时间:2026/10/2 4:06:08来源:尧图网络
PageHelper与LIMIT分页:原理、集成、坑点与深分页优化实践
回顾我这几年做 Java 后端凡是和数据库打交道的项目几乎没人能绕开分页。早期用 JDBC 手动拼LIMIT后来用 MyBatis 还得自己封装一套分页逻辑直到接触到 PageHelper 这个 MyBatis 物理分页插件才算是把“列表分页”这件又基础又琐碎的事给理顺了。今天这篇就围绕 PageHelper 和它背后真正干活的 SQL 关键字——LIMIT把原理、集成、使用、坑点一次说透。这篇文章适合谁看正在用 MyBatis 做业务的开发准备面试时被问到“分页原理”的候选人以及手上有老项目想要平滑引入分页插件的维护者。我会尽量把底层机制讲明白也会把实际项目中遇到的“怪问题”拿出来拆解争取让你读完既能上手也能在别人面前把话说清楚。1. 分页问题的根源为什么“物理分页”如此关键1.1 逻辑分页与物理分页从“全量加载”到“只取需要的数据”分页这个概念很简单一页展示 20 条用户点第二页就接着显示后面 20 条。但实现方式却有本质区别。早期很多初学者会写类似这样的代码先把表里所有数据查出来放到一个List里然后用subList(start, end)截取当前页的数据。这就是典型的逻辑分页也叫内存分页。逻辑分页的最大问题是数据量一大就崩。假设订单表有 100 万条记录每次请求都把这 100 万条查出来放在 JVM 堆里再只拿 20 条给前端这个内存开销和网络传输开销完全不可接受。更不用说多个用户同时访问时服务器内存会迅速被拖垮。物理分页则是把分页动作直接下推到数据库层通过 SQL 语句限制数据库只返回我们需要的那一页数据。以 MySQL 为例核心命令就是LIMIT offset, pageSize。数据库在存储引擎层面就只扫描并返回指定范围内的行内存和 IO 占用都小得多。这也是为什么我在项目里一直强调分页必须做“物理分页”除非你处理的数据量小到可以忽略不计否则别碰subList这种方案。1.2 让 LIMIT 变得通用主流数据库的分页语法差异很多人会误以为LIMIT是所有数据库通用的这是个大坑。LIMIT是 MySQL、PostgreSQL、SQLite 等数据库支持的语法但 SQL Server 用的是OFFSET ... FETCH NEXT ... ROWS ONLYOracle 12c 之前的主流做法是ROWNUM配合子查询12c 之后才引入了FETCH FIRST ... ROWS ONLY。这就带来一个现实问题同一个分页逻辑在不同数据库上要写完全不同的 SQL。如果项目从 MySQL 迁移到 PostgreSQL所有手写分页 SQL 都要改一遍。PageHelper 存在的一个重要意义就是把这些方言差异“屏蔽”掉。你只需要写标准查询PageHelper 根据配置的helperDialect自动生成对应数据库的分页语句。我当年接手过一个老项目底层数据库从 MySQL 切到达梦几十个 DAO 里手写的分页 SQL 改到崩溃后来统一换成 PageHelper本质问题才解决。所以我不止一次跟同事说分页这种通用能力能交给成熟插件就别自己造轮子尤其是涉及多数据库方言的场景。2. PageHelper 核心原理MyBatis 拦截器如何把查询改写成 LIMIT2.1 MyBatis 插件机制与拦截点选择PageHelper 本质上是一个 MyBatis 插件Interceptor。MyBatis 允许你在 Executor、StatementHandler、ParameterHandler、ResultSetHandler 这四个核心组件上做拦截。PageHelper 拦截的是Executor的query方法。为什么选Executor因为它是 MyBatis 执行 SQL 的入口不管是selectList、selectOne还是自定义方法最终都会走到Executor.query()。在这个位置做手脚能覆盖几乎所有查询场景而且能在 SQL 真正发往数据库之前完成改写。用大白话讲你写的select * from user where age 18是“原料”PageHelper 拦截器就是这个“加工车间”它会在 MyBatis 解析完这条 SQL、准备执行之前把语句偷偷改写成select * from user where age 18 LIMIT 0, 20。你甚至不需要改变原有 DAO 方法。2.2 从 SQL 解析到 count 查询生成一次分页请求的完整路径我们来看一次带分页的查询请求PageHelper 内部到底做了哪些事。假设业务代码是这样PageHelper.startPage(1, 10); ListUser users userMapper.selectByCondition(admin);第一步startPage方法会把分页参数页码、每页条数保存到ThreadLocal中。这一步很关键后面讲坑的时候还会再提到。第二步当userMapper.selectByCondition执行时MyBatis 进入Executor.query()PageHelper 拦截器在这里被触发。它先从ThreadLocal里取出分页参数判断当前查询是否需要分页。第三步拦截器会生成一条 count 查询语句用于计算符合条件的总记录数。这种自动生成有专门的处理逻辑对group by、distinct等情况要做区分否则统计总数会出错。第四步改写原 SQL根据配置的数据库方言生成对应的分页语句。MySQL 就是LIMITPostgreSQL 是LIMIT ... OFFSET ...SQL Server 则是OFFSET ... FETCH NEXT。第五步执行改写后的 SQL拿到当前页数据同时执行 count 查询拿到总数然后把两者封装成分页结果返回。我第一次读 PageHelper 源码时印象最深的是它对BoundSql的处理。MyBatis 中每条 SQL 都被封装在BoundSql对象里包含了最终 SQL 语句和参数列表。PageHelper 拿到BoundSql后需要重新解析参数、拼接新 SQL再构造一个新的BoundSql来替代原来的对象。这个过程复杂且容易出错所以才有了 PageHelper 在特定版本里对某些 SQL 场景支持不佳的问题。3. Spring Boot 集成 PageHelper依赖、配置与版本取舍3.1 Maven 依赖选择与版本注意事项Spring Boot 项目引入 PageHelper 很简单一个依赖搞定dependency groupIdcom.github.pagehelper/groupId artifactIdpagehelper-spring-boot-starter/artifactId version1.4.7/version /dependency如果你用的是老版本 MyBatis 项目也可以只引入核心包dependency groupIdcom.github.pagehelper/groupId artifactIdpagehelper/artifactId version5.3.3/version /dependency这里特别提醒一句版本匹配问题。PageHelper 5.x 对应 MyBatis 3.x而 pagehelper-spring-boot-starter 1.4.x 最好配合 Spring Boot 2.x 使用。如果你用的 Spring Boot 3.x需要选择支持 MyBatis 3.5 的更新版本或者单独引入 pagehelper 核心包并在配置类中注册插件。遇到“分页不生效”或“插件未注册”这类问题八成是 starter 自动配置失效而不是代码写错了。我的建议是新项目直接上官方最新稳定版本老项目在升级前先看 release notes 里的兼容性说明。3.2 配置项逐项拆解从 dialect 到 reasonable在application.yml中可以做很多定制我常用这几个pagehelper: helper-dialect: mysql reasonable: true support-methods-arguments: true params: countcountSql return-page-info: truehelper-dialect指定数据库方言。不配置时 PageHelper 会自动识别但多数据源场景下我建议显式配置。自动识别偶尔会因为连接池代理问题失败显式配置最稳妥。reasonable是否启用合理化。默认false。如果启用当页码超过总页数时会自动归一到最后一页页码小于 1 时自动归一到第一页。这个功能在面向用户的接口中很实用能避免因为前端传了个超大页码导致数据库执行深分页。support-methods-arguments是否支持接口参数透传分页参数。开启后可以不用PageHelper.startPage直接在 Mapper 方法参数里传Page子类参数。params用于配置参数映射countcountSql表示若 Mapper 方法参数中有countSql字段则使用它来自定义 count 查询。return-page-info是否返回 PageInfo 类型。开启后方法返回PageInfo时自动填充总条数等信息。还有一个容易被忽略的配置是page-size-zero默认为false。如果设置为true当pageSize0时不执行分页直接查询全部数据。某些导出功能中这个开关很好用但在线列表接口建议保持关闭。3.3 老项目集成中的常见冲突老项目集成 PageHelper 时最常遇到的就是 MyBatis 已有自定义拦截器多个拦截器之间的执行顺序问题。MyBatis 拦截器用责任链模式执行后注册的拦截器会先执行。如果你有自定义的拦截器比如数据权限拦截器、SQL 日志拦截器要留意它们会不会和 PageHelper 的执行顺序冲突。我遇到过一种情况项目里自定义了一个拦截器它会对 SQL 做字符串替换结果把 PageHelper 改写后的LIMIT 0, 10也一并替换了导致分页参数被破坏。排查了很久才发现是拦截器顺序问题。解决办法很简单在注册拦截器时明确顺序或者把自定义拦截器的逻辑限定在某类 SQL 上。不要图省事在多个拦截器里做“无差别字符串处理”这是很多诡异问题的温床。4. PageHelper 的实用姿势与常见坑4.1 startPage 的调用陷阱ThreadLocal 的前世今生PageHelper 的startPage底层是基于ThreadLocal的。这是一个特别好用也特别容易出错的机制。startPage之后下一次查询会自动使用分页参数查询完成后 PageHelper 会清理ThreadLocal。但如果你这样写PageHelper.startPage(1, 10); ListUser list userMapper.selectAll(); PageHelper.startPage(2, 10); ListRole roles roleMapper.selectAll();第二次startPage会覆盖第一次的分页参数第一个查询实际拿到的就会是第一页还是第二页经验不足的同学很容易在这种连续分页的代码里翻车。正确做法是每次查询前紧挨着调用startPage查询后马上使用结果不要穿插其他分页调用。另一个常见问题是startPage后面跟的不是查询而是其他操作。比如PageHelper.startPage(1, 10); User user userMapper.selectOne(...); ListUser list userMapper.selectAll();selectOne如果也能被 PageHelper 拦截就会先执行分页改写导致后面的查询分页参数错乱。我自己碰到过类似场景最后总结的经验就是startPage必须紧跟在真正需要分页的那条查询前面中间不要插入任何可能触发 SQL 的操作。再补充一个细节在 Spring 的Transactional方法中ThreadLocal属性照样生效但得注意事务代理和查询方法是不是同一个线程。异步调用、线程池并发等场景下ThreadLocal会失效或串号分页参数会莫名其妙被其他线程共享。遇到这种场景宁可放弃startPage改用supportMethodsArguments传参方式或者显式用Page对象作为 Mapper 方法参数。4.2 PageInfo 与 Page 对象返回的包装逻辑分页查询后的返回结果我建议使用PageInfo对象原因很简单它已经帮你封装好了 total、pageNum、pageSize、pages、isFirstPage、isLastPage、navigatePages 等一系列前端列表展示需要的属性。PageHelper.startPage(1, 10); ListUser users userMapper.selectAll(); PageInfoUser pageInfo new PageInfo(users);这里有个隐含知识点userMapper.selectAll()返回的List其实是一个Page对象PageHelper 返回的ArrayList子类。PageInfo接收这个Page对象后能从中取出 total、pageNum 等信息。所以如果你把查询结果直接返回给前端而前端又需要 total 字段请记得包装成PageInfo。有些同学只返回了List发现前端拿不到 total其实就是漏了这一步。另外注意Page对象继承自ArrayList序列化时字段传递有一定讲究。如果你用 Jackson 直接序列化Page可能带出一些不期望的字段比如countColumn、orderBy等。稳定做法是统一用PageInfo作为接口返回模型或者自己定义统一的返回 DTO。4.3 分页中的排序、条件与动态 SQL 优化分页和排序经常一起用。最佳实践是排序条件尽可能写在 SQL 里让数据库在分页之前完成排序这样每一页的数据才是连续且正确的。select idselectUserPage resultTypeUser SELECT * FROM user WHERE status #{status} ORDER BY create_time DESC /select有人会问能不能像startPage那样 PageHelper 来帮我排序PageHelper 确实支持PageHelper.orderBy(create_time desc)但个人不太推荐在业务代码里写字符串排序一方面有 SQL 注入风险另一方面字符串拼接的排序条件难以维护。排序字段我倾向于用白名单方式在后端做字段映射再拼到 SQL 中不让前端直接传任意字段名。还有一个很容易踩的性能坑在分页查询中使用select *。如果一个表有几十个字段里面还有text类型的大字段物理分页虽然只返回一页数据但查询过程中可能仍然会把大字段读入内存严重影响性能。建议分页查询只查列表页需要的字段详情接口单独查全字段。这个优化实践上往往比调 PageHelper 配置更见效。5. count 的生成与性能优化实践5.1 自动 count 查询的工作方式与优化PageHelper 在分页时会自动执行一条select count(*)类型的查询。自动生成的 count 查询会把原 SQL 的select部分替换为select count(*)同时去掉order by子句。常规场景下这是没问题的但遇到下面几种情况自动 count 可能出错SQL 中包含group by时自动生成的 count 可能统计的是分组数量还是组内行数逻辑会变得复杂。SQL 中包含distinct时简单的select count(*)无法处理去重后的统计。复杂子查询或union场景下自动改写可能生成不合法的 count 语句。遇到这种情况有两种解决方案。一种是手动分页不依赖 PageHelper 的自动 count而另一种是使用 PageHelper 支持的“自定义 count 查询”机制。PageHelper 允许你定义一个以_count结尾的 Mapper 方法来替代自动生成的 count。比如// 自定义 count 查询分页时 PageHelper 会优先调用这个方法 long countByCondition(Param(status) Integer status);再配合params配置PageHelper 会优先执行自定义 count 方法而不是去改写原查询。这在复杂统计场景下能显著提升准确性。5.2 大 offset 分页下的性能攻坚分页性能问题最典型的场景就是“深分页”。假设一页 10 条用户翻到第 100000 页SQL 会变成SELECT * FROM user ORDER BY id LIMIT 999990, 10;数据库需要把前面 999990 行全部扫描并跳过才能返回最后 10 条。这就是LIMIT关键字的最大短板。offset 越大性能越差。应对方案一基于游标cursor的分页。不传页码而是传上一页最后一条记录的 idSELECT * FROM user WHERE id #{lastId} ORDER BY id LIMIT 10;这种方案在数据分布连续、按主键排序时非常高效也是目前 C 端业务中比较推荐的方案。缺点是用户不能随意跳页只能“下一页”。应对方案二子查询延迟关联。先查出当前页主键集合再关联原表取其他字段SELECT u.* FROM user u JOIN (SELECT id FROM user ORDER BY id LIMIT 999990, 10) tmp ON u.id tmp.id;这条 SQL 让内层查询尽量只扫描主键索引减少了回表的开销。实际效果取决于表的索引情况但通常比直接大偏移量查询好很多。PageHelper 并没有完全替你解决深分页问题它只是生成了 LIMIT 语句底层的执行性能还得靠优化手段背。这也是面试官很喜欢问的一个点PageHelper 的底层是什么深分页怎么优化。一句话总结就是“SQL 层面加 LIMIT但查询性能需要你自己兜底”。5.3 与“手动改写 SQL”的取舍有些团队会因为深分页、复杂查询等问题选择放弃 PageHelper全部手写 SQL。我不否认手写 SQL 在特定场景下更可控但你要权衡代价。手写 SQL 意味着你每次都要处理页码和偏移量的换算比如(pageNum - 1) * pageSize当前数据库方言的差异count 和 list 两条 SQL 的维护排序、去重、分组场景的处理如果项目只有几个分页接口手写完全没问题。但如果业务体量大、分页接口多用 PageHelper 统一处理能省大量时间和维护成本。我通常的做法是通用列表接口用 PageHelper极端性能要求的核心查询手写 SQL二者结合而不是二选一。6. 手动 LIMIT 还是 PageHelper两种方案的取舍6.1 LIMIT 语法细节与实际执行规则前面说到了LIMIT的分页能力这里展开讲讲它的语法细节因为很多面试问题就是从这里开始的。MySQL 中LIMIT有两种写法LIMIT 10; -- 返回前 10 条 LIMIT 10, 20; -- 跳过 10 条返回接下来 20 条 LIMIT 20 OFFSET 10; -- 等价于上面跳过 10 条返回 20 条注意两种写法的区别LIMIT offset, row_count第一个参数是偏移量第二个参数是返回行数LIMIT row_count OFFSET offset则第一个是返回行数第二个是偏移量。混淆这个顺序是写 SQL 最常见的低级错误之一。还有一个常被忽视的细节LIMIT可以和ORDER BY组合也可以和WHERE组合。执行顺序上数据库通常是先WHERE过滤再ORDER BY排序最后才应用LIMIT。所以如果排序字段没有索引或者排序规则会变化分页结果可能在不同请求间出现重复或跳行。这里还有个面试中常见的问题LIMIT能不能接受表达式在 MySQL 中LIMIT后面可以接变量或表达式但在 Prepared Statement 中使用参数绑定会更安全。6.2 手写分页时如何规避注入与性能问题既然讲到了LIMIT就必须提醒安全细节。很多人写手分页时喜欢直接把页码拼到 SQL 里String sql SELECT * FROM user LIMIT offset , pageSize;这种方式极其危险。如果 offset 或 pageSize 来自前端且没有做类型校验传入负数或特殊构造值可能破坏整条 SQL 的结构。要严格使用PreparedStatement参数绑定String sql SELECT * FROM user ORDER BY id LIMIT ?, ?; PreparedStatement ps conn.prepareStatement(sql); ps.setInt(1, offset); ps.setInt(2, pageSize);数据库对LIMIT参数绑定有各自的支持程度但主流数据库都能安全处理。使用参数绑定后注入风险大幅降低同时数据库还能复用执行计划。另外还要意识到一个约束LIMIT的 offset 和 row count 本质上是整数如果业务上允许用户传入超大的 offset你需要自己判断是否合理。参数校验不仅是安全问题也是性能问题。我在接口层通常会对分页参数做最大限额限制比如 pageSize 上限 100超过就报参数异常这对防止接口被恶意刷流量也有帮助。6.3 什么时候放弃 PageHelper直接手写 LIMIT虽然我前面一直在给 PageHelper 说好话但有几个场景我会明确选择手写LIMIT。场景回归类报表比如固定维度的统计报表、即席查询SQL 往往非常复杂含有大量group by、rollup、临时表PageHelper 的自动 count 和 SQL 改写可能出错。与其调试插件行为不如稳扎稳打手写 SQL明确控制 count 和 list 两套语句。多表 join 大字段分页同样是深分页问题。手写 SQL 可以用“先查主键再回表”的模式来优化而 PageHelper 对这类查询的改写是通用的、不一定能拿到最佳执行计划。需要实时响应的超大结果集导出场景恐怕也不是分页的问题而是流式查询的问题。手写 SQL 配合流式读取比 PageHelper 更适合。做一个简单的对比总结维度PageHelper手写 LIMIT开发效率高一行代码出分页低每个接口都要处理参数跨数据库方言自动适配需要自己维护多套 SQL深分页优化常规能力不自动优化可以针对场景极致优化复杂 count 统计可能出现兼容问题完全可控SQL 注入风险低机制安全取决于写法需谨慎7. 问题排查实录那些年我踩过的 PageHelper 坑7.1 典型问题速查表下面这个表是我在实际业务和团队排查中沉淀下来的高频问题做成了速查表方便大家直接对号入座。现象可能原因解决思路分页不生效返回全部数据startPage 后没有紧跟查询或查询方法被其他拦截器提前消费检查 startPage 与查询之间是否有其他 SQL 操作分页结果 total 始终为 0返回的是包装对象而非 Page 对象或 PageInfo 构造参数错误确认查询返回的是Page或ListEntity再构造 PageInfo多数据源下分页失效PageHelper 拦截器未对第二个数据源生效或方言识别错误显式配置helper-dialect检查各数据源的 SqlSessionFactorycount 查询结果错误SQL 含 group by/distinct/union自动 count 改写不准自定义 count Mapper 方法或改用手写分页分页 SQL 中 order by 失效自动 count 会去掉 order by但主查询的 order by 被误删检查 SQL 中 order by 位置必要时手动处理出现“不可执行的 SQL”报错插件版本与 MyBatis 版本不兼容统一升级或降级版本7.2 跟 MyBatis 二级缓存配合时的特殊情况MyBatis 的二级缓存区域是按 namespaceMapper划分的。分页查询如果开启了二级缓存可能会因为缓存命中而跳过 SQL 执行此时 PageHelper 的分页拦截逻辑根本没机会触发导致 Page 信息丢失或数据不一致。同时二级缓存本身在分页场景下意义有限因为不同分页参数会导致 key 膨胀缓存命中率低。我以前排查过一个“换页后数据不正确”的线上问题最后定位到就是因为二级缓存中存了上一次查询的完整结果参数不同却复用了缓存。最终的解决办法是分页查询的 Mapper 关闭二级缓存只对字典等稳定数据开启缓存。7.3 关于大小写、参数格式等“小问题”不要小看这些“小问题”。分页参数pageNum、pageSize如果传入字符串PageHelper 在类型转换时可能抛出异常。有些前端会把页码写成1正常情况下能自动转换但如果传了abc异常信息会让人摸不着头脑。另一个隐蔽问题是PageHelper.startPage(1, 10)传入pageSize为负数或 0 时的行为。在默认配置下pageSize 小于等于 0 时不会分页。合理利用这一点可以实现“分页开关”但也会让部分接口在传错参数时静默返回全量数据一旦表数据量大线上就是事故。所以我在接入层做参数校验pageNum 必须大于 0pageSize 必须在 1 到 100 之间从源头掐断这种现象。8. 我的使用体会与几句经验总结用过 PageHelper 五六年从它早期的 4.x 版本一路用到 5.x说说个人最直观的感受。这个插件最大的价值不是帮你写那行LIMIT而是把“分页”这个横切关注点从业务代码里剥离出来。你不需要在每个 Mapper 方法里维护 count SQL 和 list SQL不需要在不同数据库之间切换语法只需要关注业务查询本身。对团队规范来说这本身就是一种约束和收敛。但它绝不是万能的。深分页优化、复杂统计、多表超大结果集这些场景下我依然会选择手写 SQL甚至用游标、流式查询等更底层的手段。工具的价值在于解决普遍问题而方案的价值在于解决具体问题。我会在项目里建立一条基本准则默认列表查询用 PageHelper核心报表、深分页接口单独评审 SQL 方案。另外一个体会是无论用哪个版本都要把源码读一读。PageHelper 的源码不算长核心类就那么几个读懂了之后很多问题都不是玄学而是机制推导的自然结果。比如你知道它是靠ThreadLocal传参就不会写出跨方法的startPage调用你知道它自动改写 count就不会把复杂统计交给它盲目执行。分页这个功能看起来简单但真正做深了里面有方言适配、执行顺序、缓存一致性、深分页优化这些门道。希望这篇内容能帮你少踩几个坑也把 PageHelper 和LIMIT这套组合用得更清楚。最后再分享一个我踩过多次的小技巧上线前一定要用真实数据量做一次分页压测不要在小数据量环境验证了就以为万事大吉——很多分页问题都是数据量上来之后才暴露的。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

游戏逆向与反作弊实战:从攻防体系到检测细节全解析 2026/10/2 4:59:27

游戏逆向与反作弊实战:从攻防体系到检测细节全解析

直接一点说,很多人一听到“游戏逆向工程”就想到外挂,一听到“反作弊”就想到内核驱动、封号、骂战。但如果你真正在这个行业待过几年,你会意识到,这其实是一套极其严密的技术攻防体系——逆向是手段,反作弊是目的&…

阅读更多 →
可信数据空间连接器:不移动数据的跨系统安全协作架构 2026/10/2 4:59:26

可信数据空间连接器:不移动数据的跨系统安全协作架构

1. 什么是可信数据空间连接器?它到底在解决什么问题?“可信数据空间-连接器技术架构设计方案”这个标题乍看像一份内部技术文档,但背后其实是一场静悄悄的数据治理革命。我从2018年开始参与工业数据平台建设,亲眼见过太多企业花几…

阅读更多 →
OpenMAIC Windows安装部署指南:多智能体AI课堂环境配置与依赖排查 2026/10/2 4:59:20

OpenMAIC Windows安装部署指南:多智能体AI课堂环境配置与依赖排查

1. 从热搜词里读懂 OpenMAIC 的真实需求1.1 为什么一个课堂平台会被反复搜"怎么安装"OpenMAIC 这个名字最近在技术圈和教育圈的搜索量涨得很明显,但如果你仔细看那些热搜词,会发现一个很有意思的现象:排在前面的不是"多智能体…

阅读更多 →
AI日报制作全流程:信息源分层、筛选标准与结构化写作实战 2026/10/2 4:59:20

AI日报制作全流程:信息源分层、筛选标准与结构化写作实战

1. 一份“AI 日报”到底在记录什么每天早上九点前,我会把过去二十四小时里跟人工智能相关的动态过一遍,筛掉噪音,留下真正值得花时间看的东西,整理成一份日报。这个习惯从 2023 年一直坚持到现在,2026 年 9 月 21 日这…

阅读更多 →
基于Python的城市交通流量数据可视化分析系统设计与实现 2026/10/2 4:59:20

基于Python的城市交通流量数据可视化分析系统设计与实现

简介:面向具备Python编程基础的数据分析、后端或GUI开发人员及交通相关专业学生,这套城市交通流量数据可视化分析系统项目实例,完整覆盖了从多源数据采集、清洗、存储、多维统计到交互式可视化与预测建模的全流程。项目采用分层架构&#xff…

阅读更多 →
AI日报制作全流程:从300条信息到12条的筛选与核实实战 2026/10/2 4:59:20

AI日报制作全流程:从300条信息到12条的筛选与核实实战

1. 一份AI日报的诞生:从信息洪流到结构化认知每天早上七点,我的手机闹钟还没响,RSS阅读器里已经堆了三百多条未读。这不是什么夸张的比喻,而是过去两年我做AI日报项目以来最真实的日常。2026年9月21日这一期,从选题到最…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉