当前位置: 首页 > news >正文

8月5号新增筛选条件

商户预警筛选功能设计:
一个「看起来简单」的筛选功能背后,隐藏了几个值得深挖的架构判断。

一、需求回顾
这个功能的起点是一句话:

连续3天未交易的通过审核商户,记录下来,方便查哪天有哪些人不交易。

随着需求的展开,它演变成了一个带有多维筛选的预警系统:

按公司信息搜索(公司名/法人/注册号)
按审核状态过滤(已通过/待审核/已驳回)
按指定上级手机号查其所有下级的流失数据
每个筛选维度背后,都有一个值得说说的架构决策。

二、筛选维度一:公司信息搜索
数据来源
公司信息(法人、注册号、公司名)本属于 cn_user_company,但我们选择了反规范化——在每日快照写入时,把这些字段冗余到 cn_user_churn_warning_record。

为什么不联表查
最直接的方案是查询时 JOIN cn_user_company:

但我没有这么做。原因:

历史快照语义:快照记录的是「统计那一天用户的状态」。如果用户之后修改了公司信息,JOIN 拿到的是现在的公司信息,而不是快照时间点的。冗余字段保证了历史快照的完整性。
查询性能:cn_user_company 有近万行,高频查询时 JOIN 每次都要关联,冗余后直接走快照表索引。
筛选简洁:搜索直接 LIKE business_name 或 LIKE register_number,不需要跨表。
代价:冗余字段在公司信息变更后不自动同步,但快照本来就是历史记录,这个代价可以接受。

三、筛选维度二:审核状态过滤
设计决策
// 前端默认传 companyStatus = 1,后端 SQL 加过滤
<if test="companyStatus != null">
and r.company_status = #{companyStatus}
</if>

默认值的选择是这里最重要的决策:默认 status=1(已通过),而不是「全部」。

理由:运营看这个页面的目的是「找需要跟进的活跃商户」,未审核或被驳回的商户在这个场景下几乎没有运营价值。所以默认过滤掉,降低认知负担。

但允许选「全部/待审核/已驳回」,给运营留了灵活空间——比如想看「即使是待审核用户也3天没交易」的情况。

四、筛选维度三:指定上级手机号
这是最有技术含量的一个维度,也是我做过几次方案选择的地方。

数据结构
系统的邀请关系通过两个字段记录:

inviter_id: 直接上级
inviter_path: /10/25/30/ 完整邀请链路径

inviter_path 是一种树形结构的路径压缩存储,用 LIKE 可以高效查任意层级的下级:

-- 查 user_id=25 的所有下级(直接+间接)
WHERE inviter_path LIKE '%/25/%'

方案选择:Java层 vs SQL层
我考虑了两种实现方式:

方案A(SQL子查询):

AND w.user_id IN (
SELECT user_id FROM cn_user WHERE inviter_path LIKE '%/X/%'
)

方案B(Java层处理):

// 先查下级列表
List<Long> subordinates = cnUserMapper.getInviterIds2(targetUserId);
// 再传给Mapper做IN过滤
query.setUserIdList(subordinates);

选择方案B,理由:

报错友好:手机号不存在时可以提前返回「该用户不存在」,而不是静默返回空数据
代码清晰:查下级和过滤预警是两个独立逻辑,放在一起的子查询难以维护
符合项目风格:getInviterIds2 在项目中已有多处复用,不新造轮子
扩展灵活:下级 ID 列表可以在 Service 层做更多处理(如限量、排重)
但方案B有个隐患:下级列表可能非常大(间接下级可能数千甚至上万)。IN 列表过长会导致 SQL 性能下降。当前数据规模下没有问题,但上规模后需要考虑分页或改用关联查询。

五、一个踩坑记录:XML <> 不转义
在实现「下级过滤」时,我在 CnUserMapper.xml 里写了:

and u.user_id <> #{getUserId}

< 在 XML 里是标签起始符,必须写成 &lt;。这导致 MyBatis 解析 XML 失败,整个应用启动退出码1。

正确写法:

and u.user_id &lt;&gt; #{getUserId}

这是 XML 开发中最经典的低级错误之一。MyBatis Mapper 文件是 XML 格式,SQL 里涉及比较运算符时必须转义:

原符号 XML 转义
< &lt;
> &gt;(严格来说 > 不强制,但建议转义)
<> &lt;&gt;
<= &lt;=
更好的防护方式是用 <![CDATA[...]]> 包裹含有特殊字符的 SQL 片段:

<![CDATA[ and u.user_id <> #{getUserId} ]]>

CDATA 块内的内容不会被 XML 解析器处理,可以写原始 SQL 字符,更直观。

六、数据快照的语义边界
筛选功能的背后,其实是「快照表」和「实时联表查询」之间的权衡。

快照表的核心价值是历史可追溯 + 查询性能,但它有一个固有的语义问题:快照是某一时刻的状态,不随时间自动更新。

这对筛选有直接影响:

筛选字段 数据时效 可能的语义问题
business_name 快照时间点 用户改了公司名后,快照里是旧名字
legal_person 快照时间点 同上
company_status 快照时间点 状态变更后快照不反映
last_trade_time 快照时间点 每天更新,较准确
当前处理方式:每次手动统计或定时任务跑时,ON DUPLICATE KEY UPDATE 会刷新当天快照,公司信息随之更新。所以实际上每天的快照是当天最新状态,只有历史快照(如昨天的)才可能有偏差。

对于运营来说,看最新一次快照(默认行为)时,数据是准确的。

七、架构总结
这个筛选功能的设计,体现了几条可以复用的原则:

原则 体现
反规范化换查询效率 冗余公司字段进快照表,避免 JOIN
默认值决定用户心智 默认 status=1,降低认知负担
Java层做报错,SQL层做过滤 下级查询在 Service 层控制边界,SQL 层做 IN 过滤
XML 特殊字符必须转义 <> → &lt;&gt;,或用 CDATA 块
快照语义需明确边界 快照是时间点状态,每日更新保证最新快照准确性
筛选功能不难,但把它做对——既高效又语义清晰——需要在每个维度上都做出合理的判断。这大概是架构工作的本质:不是找最复杂的解,而是找在当前约束下最合适的解。先读一下现有的 Mapper 和 Service 代码,再写这篇分析。先读一下现有的 Mapper 和 Service 代码,再写这篇分析。

智能体
读取商户预警相关代码
思考

http://www.jsqmd.com/news/1338032/

相关文章:

  • 2026讯灵geo十大出片品牌深度测评 价格透明不踩雷 - 工业设备
  • AI为什么总在关键时刻掉链子?:揭秘3类无法突破的底层局限与应对框架
  • 2026上海橡塑展怎么挑选展台设计搭建公司?认准高品质搭建服务商
  • 从数字孪生到企智孪生(ETA):把组织知识沉淀为可复用的智能资产【杭州联保 卢伟舜】
  • 付费使用了GLM 5.2模型,但在实际使用中,模型输出质量极差,提交工单反馈问题,结果给我自动关闭且无法再评价
  • 图片大小必须小于300K怎么弄 2026亲测有效教程 - 图片处理研究员
  • MATLAB循环中动态变量名创建:从eval到结构化数据存储的工程实践
  • 豆包表格复制到WPS变竖线:DS随心转整理Word和Excel
  • 比特米盒子刷CoreELEC教程:从安卓电视盒变身专业影音播放器
  • ManageEngine卓豪-5款高性价比SIEM替代方案推荐
  • 深入分析Xcode中SwiftUI的可视化编辑工具:Canvas、Inspector与Library
  • 从初音未来盲盒看IP衍生品设计:技术视角下的潮玩产品拆解
  • 2026年有名的AI推广企业实力参考 - 工业设备
  • 腾讯云4倍速视频审核技术解析:并行架构与多模态AI融合
  • 使用Kettle连接PostgreSQL数据库并导出Excel的完整指南
  • Web自动化实战:逆向分析正方教务系统实现一键教学评价
  • UABEA跨平台Unity资源编辑工具:从查看提取到深度修改实战指南
  • OpenClaw:基于AI智能体与Docker的视频自动化处理平台部署与实战
  • 从零搭建自主Agent框架:核心架构、代码实现与工程实践
  • GB28181图像抓拍全解析:从协议原理到工程实现
  • 2026 年现阶段唐山可靠的移动厕所源头厂家哪家可靠,蹲在路边发愁的人,这玩意儿竟能解决你的燃眉之急? - 实业推荐官
  • AI写产品文案≠复制粘贴:真正高手都在用的“语义锚点校准法”,让转化率跃升2.8倍
  • 周口学化妆培训哪家强 2026**避坑推荐 - 工业设备
  • Linux入门DAY14(高频难点:指针)
  • 从晶振到FPGA:时钟电路设计核心要点与实战避坑指南
  • I2C总线协议深度解析:从核心原理到嵌入式实战调试
  • 大模型技术选型:激进押注评估框架与实战指南
  • Redis哈希碰撞性能劣化排查与优化实战
  • 嵌入式开发USB免驱技术:原理、配置与实战应用指南
  • 彻底清除AMD显卡驱动残留:手动删除注册表右键菜单项教程