暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

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

陌溪教你学编程 2021-12-29
627

作者:陌溪

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

大家好,我是陌溪

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

签到

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

签到失败

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

小伙伴的求助

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

暴力签到

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

问题查找

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

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

### 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 年了。实现了提前一年的签到任务。

数据库记录

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

  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' 即可。

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 的实际用法,所以我做了以下一些测试

   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」,公众号上的文章也会在此同步更新,欢迎各位小伙伴一起交流学习,回复 「PDF」获取PDF笔记。

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

本公众号申请较晚,暂时没有开通留言功能,欢迎小伙伴们添加我的私人微信 coder_moxi【备注:加群】,我将邀请你加入到蘑菇博客交流群中,欢迎小伙伴们找陌溪一块聊天唠嗑,共同学习进步。最后,如果你觉得本文对你有所帮助,麻烦小伙伴们动动手指给文章点个「」和「在看」,非常感谢大家的支持。

快来找陌溪唠嗑吧

点个在看你最好看

文章转载自陌溪教你学编程,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论