java.sql.SQLException: Zero date value prohibited 异常的解决方法

使用MyBatis查询数据时候遇到这个异常,stackoverflow上一条回答解决办法是通过给jdbc链接增加zeroDateTimeBehavior参数来解决。

实际的错误还应该有:
java.sql.SQLException: Value ‘0000-00-00’ can not be represented as java.sql.Date

jdbc:mysql://yourserver:3306/yourdatabase?zeroDateTimeBehavior=convertToNull

随后查阅了官方手册,给出的解释如下。

zeroDateTimeBehavior What should happen when the driver encounters
DATETIME values that are composed entirely of zeros (used by MySQL to
represent invalid dates)? Valid values are “exception”, “round” and
“convertToNull”. Default: exception Since version: 3.1.4
http://dev.mysql.com/doc/connector-j/5.1/en/connector-j-installing-upgrading-3-0-to-3-1.html

设置zeroDateTimeBehavior 属性,当遇到DATETIME值完全由0组成时,最终的有效值可以设置为,异常(exception)一个近似值(round),或将这个值转换为null(convertToNull)

随后近一步查阅手册,三个参数的详细解释如下。

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.
http://dev.mysql.com/doc/connector-j/5.1/en/connector-j-installing-upgrading-3-0-to-3-1.html

默认情况为exception,设置这个属性会抛出一个SQLException异常,其SQLSate码为S1009。这个状态码在写存储过程处理异常时也可以用到。

convertToNull,返回null来替代0000-00-00这样的日期。

round,将日期转换为0001-01-01。

因此,出现0000-00-00 属于一个无效日期,用convertToNull属性即可。

### 解决 Spring DAO 中因零日期值引发的 TransientDataAccessResourceException 当使用 MyBatis 或其他 ORM 工具通过 Spring 数据访问层执行查询操作时,如果数据库中的某些字段存储了非法的零日期值(如 `0000-00-00`),则会抛出类似于 `java.sql.SQLException: Zero date value prohibited` 的异常[^1]。这种错误通常源于 JDBC 驱动程序无法处理无效的日期格式。 #### 原因分析 此问题的根本原因在于 MySQL 默认不允许将零日期值映射到 Java 对象中的 `Date` 类型属性上。JDBC 驱动尝试解析这些无效日期时失败并抛出了上述异常[^2]。 --- ### 解决方案 以下是几种常见的解决方法: #### 方法 1:修改 MySQL 连接配置 可以通过调整 MySQL 的连接字符串来允许读取零日期值。在应用的数据源配置文件中设置如下参数: ```properties jdbc.url=jdbc:mysql://localhost:3306/your_database?zeroDateTimeBehavior=convertToNull&serverTimezone=UTC ``` 其中的关键部分是 `zeroDateTimeBehavior=convertToNull` 参数。该参数的作用是将数据库中的零日期值转换为 SQL 查询结果集中的 `NULL` 值,从而避免触发异常[^2]。 --- #### 方法 2:自定义 ResultSet 映射逻辑 如果不想更改全局的数据库连接配置,则可以在 MyBatis 的 Mapper 文件或动态 SQL 中实现更精细的结果集映射控制。例如,在实体类对应的字段上添加判断条件以忽略零日期值: ```java public class User { private Date lastLoginTime; public void setLastLoginTime(Date lastLoginTime) { if (lastLoginTime != null && !isZeroDate(lastLoginTime)) { this.lastLoginTime = lastLoginTime; } else { this.lastLoginTime = null; // 将零日期设为空 } } private boolean isZeroDate(Date date) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); int year = calendar.get(Calendar.YEAR); return year == 0 || year < 1970; // 判断是否为零年份或其他不合理值 } } ``` 这种方法可以确保即使数据库中有零日期值也不会影响业务逻辑[^2]。 --- #### 方法 3:更新数据库表结构 最彻底的方法是从源头解决问题——清理数据库中存在的不合法日期记录。运行以下 SQL 脚本来替换所有零日期值为合理的时间戳或者 NULL: ```sql UPDATE your_table SET last_login_time=NULL WHERE last_login_time='0000-00-00'; -- OR UPDATE your_table SET last_login_time=CURRENT_TIMESTAMP WHERE last_login_time='0000-00-00'; ``` 这样不仅可以消除当前的应用级错误,还能提高数据质量[^1]。 --- ### 总结 以上三种方式各有优劣,可以根据实际需求选择合适的策略。推荐优先考虑 **方法 1** 和 **方法 3**,因为它们分别解决了环境适配性和数据质量问题;而 **方法 2** 更适合短期过渡阶段使用。 ```python def check_zero_date(): """ A Python function demonstrating how to detect and handle zero dates. This example assumes a similar logic could apply when processing results programmatically. Returns: str: Status message indicating whether the input contains invalid values. """ import datetime def validate_date(input_date): try: parsed_date = datetime.datetime.strptime(input_date, '%Y-%m-%d') return False if parsed_date.year == 0 or parsed_date.month == 0 or parsed_date.day == 0 else True except ValueError: return False sample_dates = ['2023-08-15', '0000-00-00'] valid_results = {date: validate_date(date) for date in sample_dates} return f"Validation Results: {valid_results}" print(check_zero_date()) ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值