【问题标题】:JDBC MSSQL Insert fails with error "near where"JDBC MSSQL 插入失败并出现错误“靠近位置”
【发布时间】:2017-01-10 03:27:11
【问题描述】:

我有一个奇怪的问题。我正在使用这样的准备好的语句执行插入:

try (Connection connection = connectionPool.getConnection();
    PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { //TODO: caching of PS
    int i = 1;
    ParameterMetaData pmd = ps.getParameterMetaData();
    ...
} catch (SQLException e) {
    throw new TGFIOException("Error executing SQL command " + sql, e);
}

插入语句是这样的:

 insert into dbo.CurrencyRates(RateDate, CurrencyID, Rate) values ( ?, ?, ? )

不幸的是,它失败了,出现以下异常:

com.microsoft.sqlserver.jdbc.SQLServerException: com.microsoft.sqlserver.jdbc.SQLServerException: Incorrect syntax near the keyword 'WHERE'.
    at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:190)
    at com.microsoft.sqlserver.jdbc.SQLServerParameterMetaData.<init>(SQLServerParameterMetaData.java:426)
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.getParameterMetaData(SQLServerPreparedStatement.java:1532)
    at com.jolbox.bonecp.PreparedStatementHandle.getParameterMetaData(PreparedStatementHandle.java:246)

语句中没有WHERE,所以我很困惑为什么它在元数据提取上失败......

编辑:

SQL Server = 10.50.2500.0 快捷版, Driver = 4.0 包中的 sqljdbc4.jar

另外,我使用 getParameterMetaData 是因为我需要将一些参数设置为 null,而首选方法是在需要 SQLType 的地方使用 setNull()。

EDIT2: 我已经用最新的 6.0 包中的驱动程序 sqljdbc41 进行了测试 - 结果是一样的

EDIT3: 我已经删除了对 getParameterMetaData() 的调用并且它起作用了,不幸的是它是一个应该最大可移植的通用部分,但它不适用于这个单个表(插入到同一数据库上的其他表工作正常!!!)

EDIT4: 我已经为这个表尝试了不同的插入语句,如果我跳过ps.getParameterMetaData() 并且在我调用它时失败,它们都可以正常工作。如果我尝试使用 2 个或更多参数,我会得到通常的 near WHERE 错误。如果我尝试插入一列,我会收到一条错误消息,指出列名不正确,即使它是正确的并且没有元数据调用,它也可以正常工作。我将尝试追踪驱动程序试图在下面做什么......

【问题讨论】:

  • 你确定它在执行插入语句时是否失败?似乎某些选择语句执行失败。
  • 可能是因为Statement.RETURN_GENERATED_KEYS 并且驱动程序在语句中添加了一些额外的条件来实现这一点。您可以尝试跟踪发送到服务器的语句。也可能是getParameterMetaData() 需要第二次往返数据库,并且在此期间发送了无效的语句。您使用的是哪个版本的驱动程序和哪个 SQL Server 版本?也许他们不匹配。
  • 您在哪里设置准备好的语句插入值?比如 setint 设置字符串等。
  • 请在连接字符串中添加jdbc:mysql://localhost:3306/mydb?generateSimpleParameterMetadata=true,然后尝试运行。
  • 为什么需要调用getParameterMetadata()。如果您只需要返回生成的(插入的)密钥,那么您可以简单地调用 ps.getGeneratedKeys() 并从 ResultSet 中提取密钥。

标签: java sql-server jdbc


【解决方案1】:

在对驱动程序的实际操作进行了一些跟踪之后(非常感谢a_horse_with_no_name),我得出了一些有趣的结论。

我的问题的解决方案是:

替换下面的插入语句

  • INSERT INTO CurrencyRates(RateDate, CurrencyID, Rate) VALUES ( ?, ?, ? )

有了这个声明

  • INSERT INTO CurrencyRates (RateDate, CurrencyID, Rate) VALUES ( ?, ?, ? )

这背后的逻辑是SQL驱动在后台做了一些元数据提取,它创建了一个带有以下片段的查询:... FROM CurrencyRates(RateDate WHERE ...如果你不在表名后面加上空格,但对于普通调用来说这是完全可能的!

编辑: 这显然是一个不一致的地方(抛开实际上是有效插入的内容),无论我是否调用元数据,它都应该始终如一地接受或拒绝此查询。

【讨论】:

  • 难以置信,但这确实解决了我的问题,直到版本 8.2.1.jre8 仍然存在。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2016-03-12
  • 2023-03-26
  • 2020-10-10
  • 1970-01-01
  • 2012-07-18
  • 1970-01-01
  • 2014-09-18
  • 1970-01-01
相关资源
最近更新 更多