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

Java调用SQL存储过程时日期转datetime失败,求排查方案

问题描述

我通过Java GUI向SQL Server数据库录入数据,采用SQL存储过程+Java专用方法实现。输入日期格式为YYYY-MM-DD HH:MM:SS(与数据库存储格式一致),但持续触发SQL Server异常:Conversion failed when converting date and/or time from character string。

SQL存储过程代码

CREATE  PROCEDURE spNovDogodek
@Ime nvarchar(50),
@Ekipa nvarchar (30),
@Sezona nvarchar(30),
@StartTime datetime, 
@EndTime datetime
AS

INSERT INTO dbo.Dogodek (Dogodek.Ime, Dogodek.IDEkipe, Dogodek.IDSezone, Dogodek.StartTime, 
Dogodek.EndTime)
VALUES (@Ime, dbo.fnIDEkipe(@Ekipa), dbo.fnIDSezone(@Sezona), @StartTime, @EndTime)

Java方法代码

public static void novDogodek (String Ime, String Ekipa, String Sezona, String CasZacetka, 
String CasKonca) {
    String userName = "***";
    String password = "*******";
    String serverName = "***.***.***.***";
    String dataBase = "DogodekVKlubu";
    String url = "jdbc:sqlserver://" + serverName + ":1433;DatabaseName=" + dataBase + 
";encrypt=true;trustServerCertificate=true";

try  {
    // connecting to the database
    System.out.println("Povezovanje...");
    Connection conn = DriverManager.getConnection(url, userName, password);

    Statement stmt = conn.createStatement();

    CallableStatement cstmt1 = conn.prepareCall("{call dbo.spNovDogodek(?, ?, ?, ?, ?)}");
    
     cstmt1.setString("Ime", Ime);
     cstmt1.setString("Ekipa", Ekipa);
     cstmt1.setString("Sezona", Sezona);
     cstmt1.setTimestamp("StartTime", Timestamp.valueOf(StartTime));
     cstmt1.setTimestamp("EndTime", Timestamp.valueOf(EndTime));
     
    cstmt1.execute();
    
    conn.close();
}
catch (Exception e) {
    e.printStackTrace();
    
}
finally {
}
}

我曾尝试将存储过程中@StartTime和@EndTime改为nvarchar类型,再用CONVERT(DATETIME, @变量, 103)转换,但无效;也试过Date.valueOf()(仅支持YYYY-MM-DD格式,带时间会报错),均未解决问题,想知道问题根源及排查方法。


问题根源与排查方案

1. Java代码参数名匹配错误

这是最直接的问题:Java方法定义的日期参数是CasZacetka和CasKonca,但代码中调用Timestamp.valueOf()时用的是StartTime和EndTime——这两个变量未定义,导致传递给SQL Server的不是用户输入的合法日期字符串,而是无效内容,触发转换异常。

修正代码:

cstmt1.setTimestamp("StartTime", Timestamp.valueOf(CasZacetka));
cstmt1.setTimestamp("EndTime", Timestamp.valueOf(CasKonca));

2. 日期字符串格式合法性验证

Timestamp.valueOf()要求输入严格符合YYYY-MM-DD HH:MM:SS格式,不能有任何偏差(比如多余空格、月份/日期/时间位数不足、使用非-/:分隔符等)。建议在转换前添加日志输出验证:

System.out.println("输入的开始时间:" + CasZacetka);
System.out.println("输入的结束时间:" + CasKonca);

查看输出是否完全符合格式要求,若存在格式错误,需先在GUI输入环节做格式校验。

3. 存储过程独立验证

直接在SQL Server Management Studio(SSMS)中执行存储过程,传入合法日期值测试:

EXEC spNovDogodek '测试事件', '测试队伍', '测试赛季', '2024-05-20 10:00:00', '2024-05-20 12:00:00';

若执行成功,说明存储过程及关联的fnIDEkipe、fnIDSezone函数无问题;若失败,需排查函数返回值或表结构的隐式转换问题。

4. 改用索引绑定参数避免映射错误

不要依赖参数名绑定,改用索引绑定更稳妥,确保参数顺序与存储过程定义完全一致:

cstmt1.setString(1, Ime);
cstmt1.setString(2, Ekipa);
cstmt1.setString(3, Sezona);
cstmt1.setTimestamp(4, Timestamp.valueOf(CasZacetka));
cstmt1.setTimestamp(5, Timestamp.valueOf(CasKonca));

5. 规范资源管理

代码中创建的Statement stmt未使用且未关闭,建议移除冗余代码,并使用try-with-resources自动关闭连接和CallableStatement,避免资源泄漏:

try (Connection conn = DriverManager.getConnection(url, userName, password);
     CallableStatement cstmt1 = conn.prepareCall("{call dbo.spNovDogodek(?, ?, ?, ?, ?)}")) {
    cstmt1.setString(1, Ime);
    cstmt1.setString(2, Ekipa);
    cstmt1.setString(3, Sezona);
    cstmt1.setTimestamp(4, Timestamp.valueOf(CasZacetka));
    cstmt1.setTimestamp(5, Timestamp.valueOf(CasKonca));
    cstmt1.execute();
} catch (Exception e) {
    e.printStackTrace();
}

内容的提问来源于stack exchange,提问作者Kalina

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 02:25:17