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

