获取 java.sql.SQLException: ORA-02291 可空外键

Getting java.sql.SQLException: ORA-02291 for a nullable foreign key

当我尝试将 NULL 值插入到具有另一个 table 的外键约束的列时,我得到 java.sql.SQLException: ORA-02291。根据定义,此列在子项 table 中为 NULLABLE,而它在父项中引用的列是 table.

的主键

我很困惑,为什么我会收到此异常。对此的任何帮助将不胜感激。

这里是异常和DDL

异常

org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; violated - parent key not found

            at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:249)
            at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)

DDL

ALTER TABLE childtablename ADD CONSTRAINT constraintname FOREIGN KEY ( childtablecolumn )
REFERENCES parenttable(parenttablecolumn) ON DELETE CASCADE;

来自我的 JUnit 的代码:

result = getJdbcTemplate().update(sql, new Object[]{
            notification.value1(),
            notification.value2(),
            notification.value3(), //this is for the column in contention, it is a int value and i have not initialized this variable 
            notification.value4(),
            notification.value5(),
            notification.value6(),
            notification.value7(),
            notification.value8(),
            notification.value9()
            });

事实是,我能够直接使用查询从 SQL 开发人员那里插入一条带有 NULL 值的记录。只有当我以编程方式执行此操作时才会失败。

Spring会不会是罪魁祸首??

错误消息 java.sql.SQLException: ORA-02291 表示未找到父键的约束冲突。

这意味着问题不在于您试图在子项 table 中插入一个 NULL 值,问题在于父项 table 不包含一行引用列的值为 NULL

PS : 可能是 foreign key of child table is also primary key in the parent table(除非parent有复合主键).所以它不允许在父 table.

中使用 NULL

编辑 1:在 OP 将附加信息插入问题后。

这里发生的事情是 childtablecolumn 包含 NULL 值,父 table 的 parenttablecolumn 不包含值为 NULL 的单行.

由于您没有透露您的数据访问代码,我只能猜测在将 NULL 值传送到数据库时出现问题。这是正确的做法:

PreparedStatement ps = myConnection.prepareStatement(
    "INSERT INTO childtablename (pk_id, childtablecolumn) VALUES (?, ?)");

ps.setInt(1, id);
ps.setNull(2, java.sql.Types.NUMERIC);

您需要使用 setNull 方法才能使代码正常工作。

编辑:根据您提供的单元测试代码片段,您可以试试这个(将参数明确设置为 null):

result = getJdbcTemplate().update(sql, new Object[]{
        notification.value1(),
        notification.value2(),
        null, // <--
        notification.value4(),
        notification.value5(),
        notification.value6(),
        notification.value7(),
        notification.value8(),
        notification.value9()
        });

原因是如果notification.value3() returns原始值(int)而不是对象(Integer),未分配的值将是autoboxedInteger.valueOf(0) 而不是 null,当创建对象数组时。

感谢大家的回复。

Mick 的建议奏效了,即在准备好的语句中将值显式设置为 null,并且由于我使用的是 spring jdbc 模板,在我的例子中只需传递 null 值到函数中的必要参数,如上面的代码片段所示

再次粘贴修复程序

如果您使用预处理语句,请尝试以下操作:

PreparedStatement ps = myConnection.prepareStatement(
    "INSERT INTO childtablename (pk_id, childtablecolumn) VALUES (?, ?)");

ps.setInt(1, id);
ps.setNull(2, java.sql.Types.NUMERIC);

对我的情况有效的修复(请参阅下面的线索以获取 Mick 的回答):

result = getJdbcTemplate().update(sql, new Object[]{
            notification.value1(),
            notification.value2(),
            null, //this is for the column in contention, it is a primitive int value and i have not initialized this variable, so i had to do this to make it work
            notification.value4(),
            notification.value5(),
            notification.value6(),
            notification.value7(),
            notification.value8(),
            notification.value9()
            });