You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用JDBC PreparedStatement插入闰年日期遇ORA-01839错误的解决方法

解决Oracle插入无效日期触发ORA-01839错误的方案

问题核心

插入1980-02-29时触发ORA-01839: date not valid for month specified,原因是Oracle会严格校验日期合法性——即便Java的Date对象能存储该值,Oracle接收时仍会判定为无效(注:1980是闰年,若仍触发错误,大概率是JDBC与Oracle日期格式/时区的兼容性问题,add_months函数可统一处理这类无效日期场景)。

用add_months在PreparedStatement中处理日期

add_months的特性是:当传入无效日期时,会自动将其调整为对应月份的最后一天。无需修改Java层日期处理逻辑,直接在SQL语句中调用该函数即可。

方案1:直接在SQL中处理参数

修改插入SQL,对日期参数使用add_months做自动调整:

// 修改SQL语句,用add_months处理日期参数
String personneString = "INSERT INTO personne (idPersonne, datedenaissance) VALUES (?, CASE WHEN ? IS NOT NULL THEN add_months(?, 0) ELSE NULL END)";

Date annivDate = (anniv == null) ? null : Date.valueOf(anniv);

try (PreparedStatement statementPersonne = connection.prepareStatement(personneString)) {
    statementPersonne.setInt(1, idPersonne);
    statementPersonne.setDate(2, annivDate); // 用于NULL判断
    statementPersonne.setDate(3, annivDate); // 传入add_months处理
    statementPersonne.addBatch();
    statementPersonne.executeBatch();
} catch (SQLException e) {
    System.out.println("date = " + annivDate);
    e.printStackTrace();
}

注:add_months(?, 0)仅做日期合法性校验与调整,不会改变原有有效日期的值。

方案2:精准定位当月最后一天

如果需要明确将无效日期转为当月最后一天,可结合last_day和trunc函数,逻辑更直观:

String personneString = "INSERT INTO personne (idPersonne, datedenaissance) VALUES (?, CASE WHEN ? IS NOT NULL THEN last_day(trunc(?, 'MM')) ELSE NULL END)";

Date annivDate = (anniv == null) ? null : Date.valueOf(anniv);

try (PreparedStatement statementPersonne = connection.prepareStatement(personneString)) {
    statementPersonne.setInt(1, idPersonne);
    statementPersonne.setDate(2, annivDate);
    statementPersonne.setDate(3, annivDate);
    statementPersonne.addBatch();
    statementPersonne.executeBatch();
} catch (SQLException e) {
    System.out.println("date = " + annivDate);
    e.printStackTrace();
}

备选方案:Java层预处理日期

若不想修改SQL,可在Java代码中提前校验并调整日期:

Date annivDate = null;
if (anniv != null) {
    LocalDate localDate = LocalDate.parse(anniv);
    // 检查日期是否合法,不合法则转为当月最后一天
    try {
        LocalDate.of(localDate.getYear(), localDate.getMonth(), localDate.getDayOfMonth());
    } catch (DateTimeException e) {
        localDate = localDate.with(TemporalAdjusters.lastDayOfMonth());
    }
    annivDate = Date.valueOf(localDate);
}

// 后续PreparedStatement代码保持不变
try (PreparedStatement statementPersonne = connection.prepareStatement(personneString)) {
    statementPersonne.setInt(1, idPersonne);
    statementPersonne.setDate(2, annivDate);
    statementPersonne.addBatch();
    statementPersonne.executeBatch();
} catch (SQLException e) {
    System.out.println("date = " + annivDate);
    e.printStackTrace();
}

内容的提问来源于stack exchange,提问作者Luis Angel Urena Lopez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 06:15:17