查看原文
其他

网上找的一段代码突然爆了,项目出现大Bug!

往期热门文章:

1、往期精选优秀博文都在这里了!
2、Serializable:明明就一个空接口!为什么还要实现它?
3、1.3万亿条数据查询如何做到毫秒级响应?
4、技术大佬:我去,你写的 switch 语句也太老土了吧!
5、23个带答案的Zookeeper经典面试题!

来源:www.cnblogs.com/aspwebchh/p/12220673.html
本人是做游戏服务器开发的,碰到一个需求,给符合某些要求的玩家发送道具奖励,奖励的数量根据离线的天数计算。
这个需求实现起来很简单,只需要在玩家上线的时候计算上次离线时间和当前时间间隔的天数,然后根据策划的算法,计算出道具种类与数量,发一封邮件给玩家就可以了。
计算两个时间间隔天数的函数没有现成的,自己又懒得写,就上谷歌搜了下,选了第一条结果,代码如下:
public static int differentDays(Date date1, Date date2) { Calendar cal1 = Calendar.getInstance(); cal1.setTime(date1);
Calendar cal2 = Calendar.getInstance(); cal2.setTime(date2); int day1 = cal1.get(Calendar.DAY_OF_YEAR); int day2 = cal2.get(Calendar.DAY_OF_YEAR);
int year1 = cal1.get(Calendar.YEAR); int year2 = cal2.get(Calendar.YEAR); if (year1 != year2) { //同一年 int timeDistance = 0; for (int i = year1; i < year2; i++) { if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0) { //闰年 timeDistance += 366; } else { //不是闰年 timeDistance += 365; } } return timeDistance + (day2 - day1); } else { //不同年 System.out.println("判断day2 - day1 : " + (day2 - day1)); return day2 - day1; } }
代码来源:https://www.cnblogs.com/0201zcr/p/5000977.html
把代码复制到项目里,调试下,发现没问题就直接用了,毕竟谷歌结果第一名,放心。
这段代码跑了几个月一直没问题,但是到了 2020-1-1 日那天,有玩家反馈收到了几百封奖励邮件,高兴坏了,但是出于对游戏的热爱,还是通知了运营人员。
运营把 Bug 反馈到服务器这边后我开始排查,百思不得其解的是最近几天都没有更新服务器, 而前几天服务器都稳稳地,怎么突然就出 Bug 了呢?
接下来就是分析玩家数据,结合代码逻辑确定问题所在,最终根据 Bug 的表现排除了所有可能性后,发现唯一可能出问题的地方就是那个网上复制过来的计算天数差的函数。
根据调试发现,这个函数在两个日期参数是不同的年份并且第一个日期大于第二个日期的时候,会返回一个错误的结果,比如:
differentDays("2020-1-1","2019-12-25")

理论上这么调用正确的结果是 -7,但是因为函数有 Bug,调用结果是 358。

于是本来不用发奖励,因为这种特殊情况一下子发出去 358 份,严重影响了游戏某类道具的平衡性。

最后,我改用 Java8 的日期库修复了 Bug,代码如下:

public static int differentDays(Date date1, Date date2) { if (date1 == null || date2 == null) { throw new RuntimeException("日期不能为空"); } LocalDate localDate1 = date2LocalDate(date1); LocalDate localDate2 = date2LocalDate(date2); return Generic.long2int(localDate1.until(localDate2, ChronoUnit.DAYS)); }
public static LocalDate date2LocalDate(Date date) { Instant instant = date.toInstant(); ZoneId zoneId = ZoneId.systemDefault(); LocalDate localDate = instant.atZone(zoneId).toLocalDate(); return localDate; }
至于补救方式就是统计名单,把发出去但还没有用掉的道具回收,用掉的就当福利,然后再发公告道歉,再送些其他物品弥补。
也幸好补救的及时,要是这些道具收不回来,游戏运营的策略都要大变了,我特么肯定没好果子吃了。
所以千万别在网上复制来路不明的代码乱用,如果真的要用,必须反复测试,否则哪一天突然暴雷有你受的。
往期热门文章:

1、历史文章分类导读列表!精选优秀博文都在这里了!
2、开发属于自己的第一款 IDEA 插件!
3Nginx为什么快到根本停不下来?
4、同事离职做假证,顺利拿到大公司offer,15k一下子到了24k!!!
5、一条简单的更新语句,MySQL是如何加锁的?
6、关于MySQL索引面试题的6连炮!招架的住吗?
7、MyBatis她不香吗?为啥老外却喜欢Hibernate/Jpa?
8代码对比工具,我就用这7个!
9Mybatis 中经典的 9 种设计模式!面试可以吹牛了!
10海量交易订单查询没做“重试”,一哥们“喜提”P3故障!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存