java.sql.SQLException: Cannot convert value '0000-00-00 00:00:00' from column 7 to TIMESTAMP

本文介绍了在使用JDBC从MySQL数据库读取特定零日期(如'0000-00-00 00:00:00')时可能遇到的问题,并提供了几种配置解决方案,帮助开发者避免因无法转换而引发的异常。
在Mysql数据库中使用DATETIME类型来存储时间,使用JDBC中读取这个字段的时候,应该使用 ResultSet.getTimestamp(),这样会得到一个java.sql.Timestamp类型的数据。在这里既不能使用 ResultSet.getDate(),也不能使用ResultSet.getTime(),因为前者不包括time数据,后者不包括date数据。

但是在使用ResultSet.getTimestamp()时也不是完全安全的,例如,当数据库中的TIMESTAMP类型的字段值为 '0000-00-00 00:00:00'时,使用此方法进行读取,会抛出异常:Cannot convert value '0000-00-00 00:00:00' from column 1 to TIMESTAMP,这是因为JDBC不能将'0000-00-00 00:00:00'转化为一个为一个java.sql.Timestamp,在Java中,想创建一个java.util.Date,使其值为 '0000-00-00'也是不可能的,最古老的日期应该是'0001-01-01 00:00:00'。

那么在程序中该怎么办捏? 解决方案在这里:

Datetimes with all-zero components (0000-00-00 ...) — These values can not be represented reliably in Java. Connector/J 3.0.x always converted them to NULL when being read from a ResultSet.

Connector/J 3.1 throws an exception by default when these values are encountered as this is the most correct behavior according to the JDBC and SQL standards. This behavior can be modified using the zeroDateTimeBehavior configuration property. The allowable values are:

exception (the default), which throws an SQLException with an SQLState of S1009.
convertToNull, which returns NULL instead of the date.
round, which rounds the date to the nearest closest value which is 0001-01-01.
Starting with Connector/J 3.1.7, ResultSet.getString() can be decoupled from this behavior via noDatetimeStringSync=true (the default value is false) so that you can retrieve the unaltered all-zero value as a String. It should be noted that this also precludes using any time zone conversions, therefore the driver will not allow you to enable noDatetimeStringSync and useTimezone at the same time.

所以,在JDBC URL中加入zeroDateTimeBehavior信息,既可以解决:
String url = "jdbc:mysql://10.149.51.80:3306/test?relaxAutoCommit=true&zeroDateTimeBehavior=convertToNull";
这个错误表明,Spring在尝试将一个对象(`com.huawei.mmp.bean.metadata.AigcInfo`)转换为SQL类型时失败了,因为该对象没有实现`Serializable`接口。 ### 原因分析 1. **`AigcInfo`类没有实现`Serializable`接口**: - 当Spring或Hibernate尝试将对象存储到数据库或通过JDBC传输时,对象必须可序列化。 - 如果对象未实现`Serializable`接口,JDBC驱动无法将其转换为SQL类型,从而抛出`NotSerializableException`。 2. **可能的场景**: - 尝试将`AigcInfo`对象直接存储到数据库的某个字段中(如BLOB或CLOB),但该对象不可序列化。 - 在使用MyBatis或Hibernate等ORM框架时,可能错误地将对象直接映射到数据库字段。 ### 解决方法 1. **让`AigcInfo`实现`Serializable`接口**: ```java package com.huawei.mmp.bean.metadata; import java.io.Serializable; public class AigcInfo implements Serializable { private static final long serialVersionUID = 1L; // 其他字段和方法 } ``` - 添加`serialVersionUID`以避免序列化版本不一致的问题。 2. **检查数据库映射**: - 如果`AigcInfo`是实体类的一部分,确保它正确映射到数据库表字段。 - 如果需要将对象存储到数据库,考虑使用JSON或XML格式(通过`@Convert`或自定义转换器)。 3. **检查SQL语句或ORM配置**: - 如果是MyBatis,检查`resultMap`或参数映射是否正确。 - 如果是Hibernate/JPA,检查`@Entity`和`@Column`注解的使用。 4. **调试和日志**: - 启用Spring和Hibernate的SQL日志,查看具体的SQL操作。 - 检查调用栈,定位是哪一行代码触发了异常。 ### 示例修复代码 如果`AigcInfo`需要存储到数据库的BLOB字段: ```java @Entity public class SomeEntity { @Lob private byte[] aigcInfoData; // 存储序列化后的AigcInfo public void setAigcInfo(AigcInfo info) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); try (ObjectOutputStream oos = new ObjectOutputStream(bos)) { oos.writeObject(info); this.aigcInfoData = bos.toByteArray(); } catch (IOException e) { throw new RuntimeException("Failed to serialize AigcInfo", e); } } public AigcInfo getAigcInfo() { if (aigcInfoData == null) return null; try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(aigcInfoData))) { return (AigcInfo) ois.readObject(); } catch (IOException | ClassNotFoundException e) { throw new RuntimeException("Failed to deserialize AigcInfo", e); } } } ``` ### 总结 根本原因是`AigcInfo`类未实现`Serializable`接口,导致无法序列化为SQL类型。修复方法是让类实现`Serializable`,或调整数据存储方式(如转换为JSON/XML)。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值