哈喽大家好,我是小米,一个对技术充满热情的29岁程序员!最近我们系统上线遇到了一些问题,解决之后觉得特别有收获,今天就和大家分享两件事儿,希望对你们也有帮助。
第一件事:限售问题
背景回顾
上线后运营配置了北京、天津等20个省的限售规则,但后来发现,即便新疆没有在配置范围内,用户依然能进行购买!这不禁让我们挠头了,于是开始定位问题。
首先,我们检查了限售逻辑,发现代码大致如下:
在这个逻辑里,只要请求的地址以某个配置省的编号开头,就允许购买。但问题在于,数据库里天津的编号是2,而新疆是28,所以startsWith("2")直接把新疆也算进去了!
解决方案一:改用equals写法
我们的第一反应是将startsWith改为equals,代码如下:
测试的时候,我们发现仍然有问题!比如请求参数是"27|2386|2387|13185",按理应该取到27,但结果却一直是2。这时候我们翻看了split方法的源码,发现它支持正则表达式,而单个竖线|是正则里的“或”操作符,实际分割根本没有生效。
于是,我们改成了:
这个修改后,split能够正确分割出27了,经过测试没问题。
解决方案二:细化到区县级
然而,这样的修改仍然只能匹配到省级,假如北京市大兴区允许购买,而北京市海淀区不允许购买,还是无法满足需求。
最终,我们将限售地区存储的结构改为数组形式,将请求参数也转换为数组,然后对数组内容进行比对:
通过这样细化到区县级的匹配,彻底解决了限售问题。
第二件事:商品详情页信息清空
问题现象
上线后,用户发现多数商品的详情页信息变成了空数据。经过排查,我们发现,当用户点击某个商品时,详情页就被清空了!
最终定位到如下代码:
问题在于,goods对象被JPA缓存管理,当我们设置goodsDetail=null时,这一修改直接影响了缓存中的实体对象,导致数据库中的商品详情也被清空!
解决方案:深拷贝对象
为了避免直接修改JPA的实体对象,我们改成了深拷贝的方式:
这里的KsBeanUtil.convert是我们团队的一个工具方法,用于深拷贝对象。这样一改后,生产环境终于稳定了!
JPA缓存机制解析
JPA的EntityManager会自动管理实体对象的生命周期,默认情况下,查询到的对象会被缓存。如果直接修改查询到的实体对象属性,这种变化会被自动同步到数据库,导致意外的问题。所以,在需要修改返回值但不希望影响数据库时,深拷贝是一个安全的选择。
总结
以上就是这次上线遇到的两件事儿,虽然过程一波三折,但最终通过团队的协作和不断摸索,问题都顺利解决。总结几个教训:
- 代码中多用精确匹配,减少模糊逻辑引发的问题。
- 谨慎操作持久化对象,尤其在JPA中。
- 上线后多关注用户反馈,快速响应问题,快速迭代。
END
每一次系统上线,问题的背后都是对代码和业务的深刻洞察。这次分享的两件事,包含了限售规则的优化和JPA缓存机制的深入理解,希望能给大家带来启发!如果你也遇到类似的问题,欢迎留言和我讨论哦~
小米会持续分享更多技术干货,咱们下次见!
我是小米,一个喜欢分享技术的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!