微信扫码登录过程
微信扫码登录过程
Jaron微信扫码登录过程
用户请求登陆,后端生成随机code,保存code和socket映射,拿code和微信平台申请二维码,用户扫描这个二维码,微信平台就会返回给后端openid+code,最后只需要保存openid和socket的关系
游标翻页
深翻页问题
普通翻页前端一般会有个分页条。能够指定一页的条数,以及任意选择查看第几页。
1 | select * from table limit 10000,10 |
其中10000代表需要跳过的条数,10代表跳过指定条数后,往后需要再取的条数。
需要先查询10000条进行丢弃,再取那么个10条选用。这个效率太低了
游标翻页
为了优化,我们可以加一个where条件
1 | select * from table where id>100 order by id limit 0,10 |
只要id这个字段有索引,就能直接定位到101这个字段,然后去10条记录。以后无论翻页到多大,通过索引直接定位到读取的位置,效率基本是一样的。这个id>100就是我们的游标,这就是游标翻页。
因为游标翻页每次都记住上次查询的最后位置,所以游标翻页不适合跳页,只能不断的往下翻。更适合C端的列表场景
总结
游标翻页的优点:
解决深翻页问题
解决频繁变动的列表翻页问题。
缺点:
- 无法跳页,只能不断往下翻
游标翻页更适合c端场景,用户只能不断下滑翻页。
普通翻页更适合B端场景。用户能看见总页数,能随意跳页
游标翻页技术细节
redis游标翻页
redis的zset天然适合游标翻页
1 | ZADD [KEY] [SOCRE] [VALUE] |
获取指定游标的成员
1 | Set<TypedTuple<V>> reverseRangeByScoreWithScores(K key, double min, double max, long offset, long count); |
min-max代表我们要筛选的score范围。根据正序还是倒序,我们只需要用到其中一个字段
offset代表要跳过几个,我们只需要跳过游标那一条记录,固定传1
count代表需要取几行记录。根据前端传的size
mysql游标翻页
这段代码实现了基于游标分页的逻辑,常用于高效的分页查询。下面对代码的逻辑逐步解析:
1. 输入参数
1 | public CursorPageBaseResp<Message> getCursorPage(Long roomId, CursorPageBaseReq request) |
roomId:表示目标房间 ID,用于查询消息时的筛选条件。
request:表示游标分页的请求参数,通常包括:
游标值(cursor):指示分页的起始位置。
每页大小(pageSize)。
2. 构建查询条件(wrapper)
1 | LambdaQueryWrapper<Message> wrapper = new LambdaQueryWrapper<>(); |
- wrapper 是 MyBatis-Plus 提供的查询构造器,允许以更优雅的方式构建查询条件。
3. 游标字段
1 | if (StrUtil.isNotBlank(request.getCursor())) { |
如果请求中携带了游标值(cursor),则只查询消息 ID 小于游标值的记录。
lt:表示小于(less than)的条件,确保返回的记录在游标之前。
4. 游标翻页方向
1 | wrapper.orderByDesc(Message::getId); |
按照消息 ID 降序排列,确保新消息(ID 更大)排在前面。
在游标分页中,常用降序排列来实现倒序翻页。
5. 额外查询条件
1 | wrapper.eq(Message::getRoomId, roomId); |
通过 eq 方法添加等值过滤条件:
过滤出指定房间(roomId)的消息。
过滤出状态为正常(NORMAL)的消息。
6. 分页查询
1 | Page<Message> page = page(request.plusPage(), wrapper); |
request.plusPage():通过分页请求获取分页参数(如页码和每页大小)。
page:MyBatis-Plus 提供的分页方法,用于执行分页查询。
查询结果存储在 page 中,包括:
当前页的记录集合(page.getRecords())。
分页的其他元信息(如总记录数)。
7. 计算游标位置
1 | String cursor = Optional.ofNullable(CollectionUtil.getLast(page.getRecords())) |
获取下一页游标:
从当前页的记录中获取最后一条记录。
提取最后一条记录的消息 ID 作为下一页的游标。
如果没有记录,游标为 null。
Optional 和 CollectionUtil.getLast:
避免空指针异常的优雅写法。
8. 是否最后一页
1 | Boolean isLast = page.getRecords().size() != request.getPageSize(); |
如果当前页的记录数小于请求的分页大小(pageSize),说明已经是最后一页。
isLast:布尔值,用来指示是否还有下一页。
9. 返回结果
1 | return new CursorPageBaseResp<>(cursor, isLast, page.getRecords()); |
CursorPageBaseResp 是返回值对象,包含以下信息:
cursor:下一页的游标位置,用于后续分页请求。
isLast:是否是最后一页。
page.getRecords():当前页的记录集合。
代码的整体逻辑
根据输入的 roomId 和游标构建查询条件。
通过分页查询获取指定范围的记录。
计算返回给前端的下一页游标和是否最后一页的标志。
返回包含游标、分页结果和是否最后一页的响应。
使用场景
实时消息加载:例如聊天记录分页,按时间或 ID 降序返回更早的消息。
高效数据加载:游标分页比传统分页效率更高,尤其在数据量大时表现更优,因为它避免了偏移量(offset)查询。
改进建议
缓存优化:在高频分页场景下,可考虑将分页结果缓存到 Redis。
并发控制:支持多用户同时请求分页时的正确性和性能保障。
异常处理:需要确保查询结果为空或发生异常时,返回合理的默认值或错误信息。

