4

我有一个使用严格模式的 MySQL 数据库,所以当我插入一行时我需要填充所有 NOT NULL 值。我创建的 API 仅使用 DUPLICATE KEY UPDATE 功能来执行插入/更新。

如果插入了预期的任何 NOT NULL 属性,客户端应用程序会抱怨。

基本示例(id 是主键,有两个字段不是 NULL aaa 和 xxx)

INSERT INTO tablename (aaa, xxx, id ) VALUES ( "value", "value", 1)
ON DUPLICATE KEY UPDATE aaa=VALUES(aaa), xxx=VALUES(xxx)

到目前为止一切都很好。插入后,系统将允许进行更新。不过,仅更新其中一个字段时出现以下错误。

INSERT INTO tablename (aaa, id ) VALUES ( "newValue", 1)
ON DUPLICATE KEY UPDATE aaa=VALUES(aaa)

java.sql.SQLException: Field 'xxx' doesn't have a default value

此异常是谎言,因为该行已被插入并且 xxx 属性具有“值”作为值。我希望以下句子等同于:

UPDATE tablename SET aaa="newValue" WHERE id=1

如果有人能对这个问题有所了解,我会很高兴。

编辑:

我可以成功地使用 PhpMyAdmin 中的 SQL 查询来更新一个字段,所以恐怕这不是 SQL 问题,而是 JDBC 的驱动程序问题。那可能没有解决办法。

@Marc B:您的见解可能是正确的,并且可以表明我刚刚描述的内容。这意味着 JDBC 中存在一个错误,因为它不应该检查何时插入是 ON DUPLICATE 类型,因为毕竟可能存在该行的默认值。无法提供真实的表格数据,但我相信上面的解释都很清楚。

@ruakh:它不会插入失败,我也不期待延迟验证。我的一个要求是使用相同的查询完成插入/更新,因为 servlet 不知道该行是否存在。JAVA API 服务仅无法更新插入完成时已填充的 NOT NULL 字段的行。例外是谎言,因为该字段确实具有默认值,因为它是在更新之前插入的。

4

1 回答 1

1

这是典型的 DRY/SRP 失败案例;为了不重复代码,您创建了一个违反单一责任原则的函数。

语句的语义INSERT是您期望没有冲突的行;该ON DUPLICATE KEY UPDATE选项只是为了避免处理代码内部的冲突,需要另一个单独的查询。这与语句完全不同,在UPDATE语句中您希望至少存在一个匹配的行。

想象一下,MySQL 只会在INSERT不冲突时检查列,并且由于某种原因刚刚从数据库中删除了一行,并且您希望执行更新的代码必须处理它不期望的异常。鉴于语句行为的不同,最好将插入和更新逻辑分开。

抛开理论不谈,当查询运行时,MySQL 会组合一个执行计划。在INSERT声明的情况下,它必须假设它在尝试时可能会成功,因为这是最优化的策略。它可以防止必须检查索引等,只是后来才发现缺少一列。

这是按设计而不是 JDBC 中的错误。

于 2012-11-16T13:27:59.430 回答