mysql数据库中日期类型为datetime,而用mybatis映射失败,报java.sql.SQLException: Cannot convert value '0000-00-00 00:00:

环境:mysql数据库+mybatis

mysql的某个字段为日期,它的类型用的是datetime。然后框架用mybatis,然后查询的时候进行映射操作是报

java.sql.SQLException: Cannot convert value '0000-00-00 00:00:00' from column 7 to TIMESTAMP. 
解决有关资料:
在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";

<think> 我们正在解决一个特定的异常:`org.springframework.dao.TransientDataAccessResourceException: Error attempting to get column 'update_time' from result set. Cause: java.sql.SQLException: Value '0000-00-00 00:00:00' can not be represented as java.sql.Timestamp` 这个问题的根本原因是:数据库中的`update_time`字段的值为`'0000-00-00 00:00:00'`,而Java的`java.sql.Timestamp`无法表示这个值(因为它不符合Java中的日期时间范围,Java要求年份至少为1970)。 解决方案的核心思路:避免从数据库中得到这样的非法值,或者在得到这样的值时能够进行转换处理。 参考站内引用[^1]提到了类似的问题(虽然错信息不完全相同,但都是关于从结果集获取列的问题),但并没有直接给出解决这个特定问题的办法。不过,我们可以根据经验提供以下几种解决方案: 1. **修改数据库中的非法日期值**:将数据库中所有`'0000-00-00 00:00:00'`的值修改为一个合法的默认值(例如`1970-01-01 00:00:00`或者`NULL`)。这是最彻底的解决方法,但需要确保业务逻辑允许。 2. **修改数据库表结构**:将`update_time`字段的默认值设置为一个合法的值(如`NULL`或一个具体的合法日期),并设置字段允许为`NULL`(如果业务允许)。 3. **在数据访问层处理**:在查询时,通过SQL语句将非法日期转换为合法日期或`NULL`。例如,使用MySQL的`IF`或`CASE`语句: ```sql SELECT IF(update_time='0000-00-00 00:00:00', NULL, update_time) AS update_time, ... FROM table; ``` 或者使用MySQL的`NULLIF`函数: ```sql SELECT NULLIF(update_time, '0000-00-00 00:00:00') AS update_time, ... FROM table; ``` 4. **在数据库连接字符串中添加参数**(针对MySQL): 在JDBC连接URL中添加参数`zeroDateTimeBehavior`,该参数用于指定当遇到`0000-00-00`这样的日期时的处理方式。有以下几种选项: - `convertToNull`:转换为`NULL` - `round`:转换为最近的日期(如`0001-01-01`) - `exception`(默认):抛出异常 示例:在连接字符串中添加`zeroDateTimeBehavior=convertToNull` ``` jdbc:mysql://localhost:3306/dbname?zeroDateTimeBehavior=convertToNull ``` 这样,当查询到`0000-00-00`时,驱动会将其转换为`NULL`,从而避免异常。 5. **在MyBatisMyBatis-Plus中自定义类型处理器**(TypeHandler): 可以编写一个自定义的`TypeHandler`,专门处理`java.sql.Timestamp`类型,当遇到`0000-00-00 00:00:00`时,将其转换为`null`或一个默认的合法日期。 示例自定义类型处理器: ```java @MappedTypes(Timestamp.class) public class CustomTimestampTypeHandler extends BaseTypeHandler<Timestamp> { @Override public void setNonNullParameter(PreparedStatement ps, int i, Timestamp parameter, JdbcType jdbcType) throws SQLException { ps.setTimestamp(i, parameter); } @Override public Timestamp getNullableResult(ResultSet rs, String columnName) throws SQLException { String dateTimeString = rs.getString(columnName); if ("0000-00-00 00:00:00".equals(dateTimeString)) { return null; } return rs.getTimestamp(columnName); } @Override public Timestamp getNullableResult(ResultSet rs, int columnIndex) throws SQLException { String dateTimeString = rs.getString(columnIndex); if ("0000-00-00 00:00:00".equals(dateTimeString)) { return null; } return rs.getTimestamp(columnIndex); } @Override public Timestamp getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { String dateTimeString = cs.getString(columnIndex); if ("0000-00-00 00:00:00".equals(dateTimeString)) { return null; } return cs.getTimestamp(columnIndex); } } ``` 然后,在MyBatis配置中注册这个处理器,或者在字段上通过`@TableField`注解指定: ```java @TableField(value = "update_time", typeHandler = CustomTimestampTypeHandler.class) private Timestamp updateTime; ``` 6. **使用MyBatis-Plus的字段自动填充功能**:如果不希望数据库中出现`0000-00-00 00:00:00`,可以在插入或更新时自动填充当前时间。这样可以避免非法值。但这种方法不能解决已有的非法值。 总结:建议优先考虑方案4(修改数据库连接字符串)或方案1(修改数据库中的数据),因为这两种方法改动最小且最有效。如果无法修改数据库或连接字符串,则可以采用方案5(自定义类型处理器)来处理。 根据具体情况选择最合适的方案。 §§相关问题§§ 1. 如何修改MySQL中的非法日期值? 2. 如何在MyBatis-Plus中自定义类型处理器? 3. MySQL的JDBC连接字符串参数`zeroDateTimeBehavior`还有哪些可选值? </think> ### 解决 `org.springframework.dao.TransientDataAccessResourceException` 错误的方法 该错误的核心问题是:数据库中的 `update_time` 字段值为 `0000-00-00 00:00:00`(非法时间戳),而 Java 的 `java.sql.Timestamp` 无法解析此值。以下是分步解决方案: --- ### 解决方案 #### 1. **修改数据库字段默认值(推荐)** - 将 `update_time` 的默认值改为合法的 `NULL` 或有效时间戳(如 `1970-01-01 00:00:01`): ```sql ALTER TABLE your_table MODIFY COLUMN update_time TIMESTAMP NULL DEFAULT NULL; ``` - **修复后效果**: 非法值 `0000-00-00` 被替换为 `NULL`,避免触发异常[^1]。 #### 2. **JDBC 连接参数配置(快速修复)** -MySQL 连接 URL 中添加参数 `zeroDateTimeBehavior=convertToNull`: ```java jdbc:mysql://localhost:3306/db_name? zeroDateTimeBehavior=convertToNull&useSSL=false ``` - **作用**:自动将 `0000-00-00` 转为 `NULL`,而非抛出异常[^1]。 #### 3. **MyBatis-Plus 类型处理器(代码层修复)** - 创建自定义类型处理器 `CustomTimestampTypeHandler.java`: ```java public class CustomTimestampTypeHandler extends BaseTypeHandler<Timestamp> { @Override public void setNonNullParameter(...) { /* 正常设置 */ } @Override public Timestamp getNullableResult(ResultSet rs, String columnName) throws SQLException { String rawValue = rs.getString(columnName); if ("0000-00-00 00:00:00".equals(rawValue)) { return null; // 拦截非法值 } return rs.getTimestamp(columnName); } } ``` -实体类中指定处理器: ```java public class YourEntity { @TableField(typeHandler = CustomTimestampTypeHandler.class) private Timestamp updateTime; } ``` #### 4. **清理数据库非法数据** - 修复现有非法数据: ```sql UPDATE your_table SET update_time = NULL WHERE update_time = '0000-00-00 00:00:00'; ``` #### 5. **调整字段类型为 `DATETIME`** - 如果业务允许,改用更宽松的 `DATETIME` 类型: ```sql ALTER TABLE your_table MODIFY COLUMN update_time DATETIME DEFAULT NULL; ``` --- ### 原因分析 - MySQL 的 `TIMESTAMP` 类型取值范围为 `1970-01-01 00:00:01` 至 `2038-01-19 03:14:07`,`0000-00-00` 超出此范围。 -MyBatis-Plus 尝试将非法值映射到 `java.sql.Timestamp` 时,触发 `SQLException`,最终抛出 Spring 的 `TransientDataAccessResourceException`[^1]。 --- ### 预防措施 1. 数据库设计时设置字段默认值为 `NULL` 或合法时间戳。 2. 启用 MyBatis-Plus 的自动填充功能,确保写入合法时间: ```java @TableField(fill = FieldFill.INSERT_UPDATE) private Timestamp updateTime; ``` 3. 在测试阶段插入边界值(如 `1970-01-01`)进行验证。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值