如何使用 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.");
}
}
我正在使用 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.");
}
}