前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >官方JDK的BUG?蘑菇签到又出问题啦!

官方JDK的BUG?蘑菇签到又出问题啦!

作者头像
陌溪
发布2022-01-05 09:35:02
3810
发布2022-01-05 09:35:02
举报
文章被收录于专栏:陌溪教你学编程

作者:陌溪

陌溪的学习笔记:http://note.moguit.cn

大家好,我是陌溪

最近,我和遇见一块完成了蘑菇签到模块的上限,让各位小伙们一起打卡参与社区的建设~

签到

但是,在 20211226 日,蘑菇群里的小伙伴反馈签到成功,但是当日显示未签到,签到积分也正常发放了。

签到失败

在蘑菇问答,也有小伙伴发帖求助,竟然想让我补发10张签到卡!

小伙伴的求助

甚至还写了连续签到脚本,暴力签到 100 次(现在已经加了一个防表单重复提交的校验了~),但都是出现这个问题。

暴力签到

看到这里心里一咯噔。于是去用户签到表中查询了 当前签到日期为 '2021-12-26' 的记录,一条都没有。完犊子了,没签到成功,积分也给了。这群小伙伴补偿他们积分没事,扣积分还得了!

问题查找

于是也去签到(试试趁着 BUG 多蹭积分),发现第一次签到会提示签到成功,就如上图所看到的那样,但是立即签到按钮没有变灰,用户还可以继续点击签到。

第二次签到会报数据库唯一索引异常,这里唯一索引是:使用 用户uid签到天 组合的唯一索引,在记录上隔绝了一天多签。把出现的错误信息,复制到文本上。

代码语言:javascript
复制
### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '8fdd1507815ddbe47319a2eaae9f2d43-2022-12-26' for key 't_sign_in_record.user_uid&sign_date' ### The error may exist in com/moxi/mogublog/xo/mapper/SignInRecordMapper.java (best guess) ### The error may involve com.moxi.mogublog.xo.mapper.SignInRecordMapper.insert-Inline ### The error occurred while setting parameters ### SQL: INSERT INTO t_sign_in_record ( uid, user_uid, sign_date, sign_type, status, create_time, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ? ) ### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '8fdd1507815ddbe47319a2eaae9f2d43-2022-12-26' for key 't_sign_in_record.user_uid&sign_date' ; Duplicate entry '8fdd1507815ddbe47319a2eaae9f2d43-2022-12-26' for key 't_sign_in_record.user_uid&sign_date'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '8fdd1507815ddbe47319a2eaae9f2d43-2022-12-26' for key 't_sign_in_record.user_uid&sign_date'

我仔细看了下数据,首先映入我眼帘,是 '2022-12-26' 这一串数字

嗯???咋肥事!!为什么时间会多 1 年,明明小伙伴都是在 '2021-12-26' 签到的,为啥到了今天就变成了 '2022-12-26' 呢,这块的签到逻辑代码之前一直都是稳定运行的。

然后,又去查找 2022-12-26 签到记录。好家伙,小伙伴们的签到记录都在 2022 年了。实现了提前一年的签到任务。

数据库记录

既然是时间问题。那么翻查下代码,看到了如下代码,感觉毫无违和感。

代码语言:javascript
复制
  public String today(){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd");
        Calendar now = Calendar.getInstance();
        return simpleDateFormat.format(now.getTime());
    }

    public String yesterday(){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd");
        Calendar now = Calendar.getInstance();
        now.add(Calendar.DAY_OF_MONTH, -1);
        return simpleDateFormat.format(now.getTime());
    }

于是通过 main 函数运行了一下代码,时间居然返回的是 today 居然是 2022-12-26!!

问题修复

至此,找到了签到不显示已签到且重复签到报错的问题。

"YYYY-MM-dd" 改为 "yyyy-MM-dd" ,运行恢复正常,输出为 2021-12-26

同时,编写SQL,将用户 '2022-12-26' 签到日期,批量更新为 '2021-12-26' 即可。

代码语言:javascript
复制
update t_sign_in_record set sign_date = '2021-12-26' where sign_date = '2022-12-26'

问题讨论

那么问题来啦,为啥 20211226 号签到,就会出现问题呢??

查阅了一下官方的 JDKSimpleDateFormat 格式化方法 ,自 JDK7 以后 新增了格式 Y

文档:https://tool.oschina.net/apidocs/apidoc?api=jdk_7u4

但是文档中并没有给与 Y 的实际用法,所以我做了以下一些测试

代码语言:javascript
复制
   public static void main(String[] args) {
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
        System.out.println(sdf1.format(new Date()));
        SimpleDateFormat sdf2 = new SimpleDateFormat("YYYY-MM-dd");
        System.out.println(sdf2.format(new Date()));

        Calendar calendar2= Calendar.getInstance();
        //2021-12-25
        calendar2.set(2021, Calendar.DECEMBER, 25);
        Date strDate2 = calendar2.getTime();
        Calendar calendar1 = Calendar.getInstance();
        //2021-12-26
        calendar1.set(2021, Calendar.DECEMBER, 26);
        Date strDate1 = calendar1.getTime();
        Calendar calendar3 = Calendar.getInstance();
        //2021-12-31
        calendar3.set(2021, Calendar.DECEMBER, 31);
        Date strDate3 = calendar3.getTime();

        Calendar calendar4 = Calendar.getInstance();
        //2021-12-31
        calendar4.set(2022, Calendar.JANUARY, 1);
        Date strDate4 = calendar4.getTime();

        System.out.println(sdf2.format(strDate2));
        System.out.println(sdf2.format(strDate1));
        System.out.println(sdf2.format(strDate3));
        System.out.println(sdf2.format(strDate4));
    }
2021-12-26
2022-12-26
2021-12-25
2022-12-26
2022-12-31
2022-01-01

上述测试中返回的 2022 年的日期均是在跨年周。也就是说 20211226 号刚好是周日,属于跨年周的第一天。那么到明年的第一天之前这些天的时间,如果使用 YYYY-MM-dd 时间都会显示为明年。

YYYYweek-based yearISO 8601 规定的。2021-12 -26 号这一天,按周算年份已经属于 2022 年了,格式化之后就变成 2022 年,后面的月份日期不变。

总结

YYYY-MM-ddyyyy-MM-dd 的区别目前出现只在跨年周才会有问题。很有可能是 YYYY 的用法不应该在这种格式化场景。所以如果正常开发,后端还是使用 yyyy-MM-ddYYYY 的业务场景到现在我也没想到,如果有了解的小伙伴也欢迎一起来探讨~

好了,本期就到这里啦

我是陌溪,我们下期再见~

博主就职于字节跳动商业化部门,一直在维护校招笔记仓库 LearningNote「在Gitee上已有 4.5k star,仓库地址 https://gitee.com/moxi159753/LearningNotes」

同时,想要丰富项目经验的小伙伴,可以参考我维护的开源微服务博客项目:蘑菇博客「 Gitee 官方推荐项目,博客类搜索排名第一,在 Gitee 已有 4.1K star,仓库地址:https://gitee.com/moxi159753/mogu_blog_v2 」。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 陌溪教你学编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题查找
  • 问题修复
  • 问题讨论
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档