如何使用 Spring JDBCTemplate 从唯一约束冲突中恢复?

How to recover from a unique constraint violation using Spring JDBCTemplate?

我正在使用 spring jdbcTemplate 和 HSQLDB 将数据插入到 PROFILE table 中,该 PROFILE 有 3 列应用了 UNIQUE 约束,即用户名、phone 号码、驾驶执照数字。

我能够使用错误代码识别唯一约束违规。但是由于有多个具有唯一约束的列,此信息不足以识别列并显示适当的错误消息。

有什么实现方法吗?

没有标准的方法可以做到这一点。您可以解析异常消息以查找违反的约束名称。这是一个简单的例子:

public class HSqlDbTest {
    public static void main(String[] args) throws Exception {
        String url = "jdbc:hsqldb:mem:test";
        Class.forName("org.hsqldb.jdbcDriver");
        try (Connection connection = DriverManager.getConnection(url, "sa", "")) {
            String createTableSql = "" +
                    "create table test (" +
                    "  a integer not null,            " +
                    "  b integer not null,            " +
                    "  constraint a_uniq unique (a),  " +
                    "  constraint b_uniq unique (b)   " +
                    ")                                ";
            try (Statement statement = connection.createStatement()) {
                statement.executeUpdate(createTableSql);
            }

            try (PreparedStatement statement = connection.prepareStatement("insert into test (a, b) values (?, ?)")) {
                statement.setInt(1, 1);
                statement.setInt(2, 1);
                statement.executeUpdate();

                statement.setInt(1, 2);
                statement.setInt(2, 1);
                statement.executeUpdate();
            } catch (SQLIntegrityConstraintViolationException e) {
                Pattern pattern = Pattern.compile("integrity constraint violation: unique constraint or index violation; (\w+) table: (\w+)");
                Matcher matcher = pattern.matcher(e.getMessage());
                if (matcher.matches()) {
                    String constraintName = matcher.group(1);
                    String tableName = matcher.group(2);
                    System.out.printf("Violated constrant \"%s\" in the table \"%s\"\n", constraintName, tableName);
                }
            }
        }
    }
}

但是我劝你不要走这条路。异常消息不是标准的,如果您更改数据库,则可能会更改。如果有多个约束违规,你只会得到第一个。

你应该做的是将 select 分开到你的 table 中来检查 phone 号码或用户名是否已经注册。这是完成任务的更可靠的方式。

你能做的就是抓住DuplicateKeyException。从这里您可以测试哪些字段可能导致问题。这样做的好处是您不需要解析供应商实施的异常消息

public void updateWidget(long id,
                         String name,
                         String category) {
    try {
        jt.update("update WIDGET" +
                  "   set DISPLAY_NAME = ?" +
                  "      ,CATEGORY = ?" +
                  " where ID = ?",
                  name,
                  category,
                  id);
    } catch (DuplicateKeyException ex) {
        // perform tests in turn, you could also perform a query to return
        // all violation counts if it is more efficient.
        if (jt.queryForObject("select count(1)" +
                              "  from WIDGET" +
                              " where NAME = ?",
                              Integer.class,
                              displayName) > 0) {
            throw new IllegalArgumentException(
                    "Widget name may not be duplicated.");
        }
        LOG.warn("Some unique constraint violation occurred: {}",
                 ex.getMessage(), ex);
        throw new IllegalArgumentException(
                "Some unique constraint violation occurred.");
    }
}