0

我有一个查询,它试图在表中插入一行。由于主键约束失败,查询可能会失败,因为已经存在具有该 ID 的行。

我可以在尝试插入之前检查这一点,但我也可以通过检查 SQLException 的 SQL 状态来检测这一点。这是做这种事情的有效方法吗?还是我应该事先做明确的检查?

我问的原因是,如果我必须在执行插入之前进行显式检查,我将不得不锁定我正在检查的表以防止不一致。使用错误代码检查意味着我不必锁定表。

事先检查

try {
    con.setAutoCommit(false);
    con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
    Statement statement = con.createStatement();
    ResultSet rs = statement.executeQuery("SELECT * FROM SomeTable WHERE Id = 123");
    if(rs.next()) {
        con.setAutoCommit(true);
        System.err.println("Entry with Id 123 already exists!");
        return;
    }
    statement = con.createStatement();
    statement.executeQuery("INSERT INTO SomeTable(Id) VALUES(123)");
    con.commit();
    con.setAutoCommit(true);
} catch(SQLException e) {
    // These 2 lines actually need to be wrapped in a try/catch too.
    con.rollback();
    con.setAutoCommit(true);
}

错误代码检查

try {
    Statement = con.createStatement();
    statement.executeQuery("INSERT INTO SomeTable(Id) VALUES(123)");
} catch(SQLException e) {
    if(e.getSQLState().equals("23505"))
        System.err.println("Entry with Id 123 already exists!");
}
4

3 回答 3

1

您的“错误代码检查”方法是有效的,并且确实是惯例。请注意,您还可以为违反的 SQL 约束的名称解析异常 Message 属性,这就是为什么将约束细化是一个好主意(即,在创建许多简单约束而不是一些复杂约束时会出错)并给每个人一个有意义的名字。

于 2011-10-17T10:54:46.047 回答
0

就个人而言,我更喜欢围绕这些事情进行防御性编码。我会写我的查询如下:

INSERT INTO SomeTable(ID)
SELECT 123
WHERE NOT EXISTS (SELECT 1 FROM SomeTable WHERE id = 123)

当然,您必须根据您的 SQL 风格修改该查询。也许:

SELECT 123
FROM DUAL 
WHERE NOT EXISTS...

插入后,您可以测试受影响的行数并确定是否存在 PK 违规。

于 2011-10-15T04:37:08.833 回答
-1

您应该首先通过对 PK 使用序列或自动增量列来避免此类错误。

但是,仍然需要正确处理 SQLExceptions,因为可能会发生各种其他错误。

于 2011-10-15T04:58:38.973 回答