1.问题描述

java.sql.SQLDataException: Cannot convert string ‘2021-4-21’ to java.sql.Timestamp value

笔者近期学习 JDBC ,测试 user 类实现方法时,由于之前手工注入了几条时间格式不符合规范的数据,导致现在,查询报错。

2.解决办法

更改数据库
登陆数据库,单独修改 那几条日期格式异常的数据,

XXXX-X-XX 改成 XXXX-XX-XX

提交事务。就好了。

源码

    @Override
    public List<User> findAll() {
        String sql = "select username, gender, birthday, mobile from user;";
        return template.query(sql, new BeanPropertyRowMapper<>(User.class));
    }

测试用例输出

5月 03, 2021 5:32:43 下午 com.alibaba.druid.support.logging.JakartaCommonsLoggingImpl info
信息: {dataSource-1} inited
User(username=zhangsan, password=null, gender=M, birthday=2021-04-21, mobile=123456, mail=null)
...

3.其他办法

3.1 添加配置参数

现在是2021年5月,网上搜到 CSDN 解决办法说:

jdbc.properties 配置文件添加 url 额外参数:自动提交和零时区转换,但我早就这样写了,没效果。不过你可以试试:

url=jdbc:mysql:///yourdatabase?relaxAutoCommit=true&zeroDateTimeBehavior=convertToNull
3.2 添加转换方法

现在是2021年5月,网上搜到 [Stack overflow] How to convert java.util.Date to java.sql.Date? 提到:

这两个时间库,已经过时了,不要转化他们了。罗列一堆版本更替的图。

但答案区,还是有人直截了当给出转换写法:

public class MainClass {

  public static void main(String[] args) {
    java.util.Date utilDate = new java.util.Date();
    java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());
    System.out.println("utilDate:" + utilDate);
    System.out.println("sqlDate:" + sqlDate);
  }
}

于是,我尝试将引入包改为 java.sql.Date ,并在 user 类添加 set 方法:

    public void setBirthday(Date birthday) {
        this.birthday = new java.sql.Date(birthday.getTime());
    }

运行测试仍然报错,因为异常数据,已经定死在数据库了。

此外,我在前端,尝试注册一个用户,然后看后台数据库,日期格式也是 XXXX-XX-XX

这说明

  • BeanPropertyRowMapper 运行流程,不走 user 类。
  • 日期格式和前端样式 input 的属性 DateDateTimeStamp 相关,和引入包无关。

4.避坑指南

  • 首先,直觉上倾向于引入名字相关的类。比如处理与数据库交互的 dao 时,引用时间类型的包,从直觉上看,应该倾向于选择 sql 相关的,即使报错,可能会尽早发现:
import java.sql.Date;
  • 其次,时间格式要统一 XXXX-XX-XX ,无论前端后端,写测试用例,注册用户时。

  • 最后,快速展开 找不同游戏环节 ,报错时,根据异常信息提示,定位数据库,找到时间格式和其他不同的数据,手动修改。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐