我正在使用postgreSql和Java,这是eclipse控制台中显示的错误
org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "km_rel_user_test_details_pkey",
这里错误的原因是(我猜)由于数据库中存在重复键, 我已经编写了一个while循环来处理这个异常,我只是想知道,这种方法是否正确并且适用于所有情况,发现/要求改进的任何错误都将受到赞赏,在此先感谢,这是我的java方法。
public String saveConceptTestDetails(String testId,String userId,String selected_ans, String check_user_save, String conceptTestOrder , int ans) {
boolean isInserted=false;
String newId1=null;
while(!isInserted){
try{
newId1=getNextVal(DBKeys.SEQ_REL_USER_TEST_DETAILS); // this is what generatres new Id
Hashtable resultHash=executeUpdate(new StringBuffer(" insert into "+DBKeys.TABLENAME_REL_USER_TEST_DETAILS+" ("+DBKeys.COLUMNNAME_REL_USER_TEST_DETAILS_ID+","+DBKeys.COLUMNNAME_REL_USER_TEST_DETAILS_TESTID+","+DBKeys.COLUMNNAME_REL_USER_TEST_DETAILS_USERID+","+DBKeys.COLUMNNAME_REL_USER_TEST_DETAILS_CREATEDDT+","+DBKeys.COLUMNNAME_REL_USER_TEST_DETAILS_MODIFIEDDT+","+DBKeys.COLUMNNAME_REL_USER_TEST_DETAILS_SELECTED_ANS+","+DBKeys.COLUMNNAME_REL_USER_TEST_DETAILS_CHECK_USER_SAVE_TEST+","+DBKeys.COLUMNNAME_REL_USER_TEST_DETAILS_TEST_TYPEORDER+","+DBKeys.COLUMNNAME_REL_USER_TEST_DETAILS_TEST_VERSION+","+DBKeys.COLUMNNAME_REL_USER_TEST_DETAILS_SAVEANS+")values ("+newId1+","+testId+","+userId+",current_date,current_date,"+selected_ans+","+check_user_save+","+conceptTestOrder+",0,"+ans+")"));
isInserted=true;
}
catch (Exception e) {
System.out.println("Exception");
isInserted=false;
}
}
return newId1;
}
答案 0 :(得分:2)
使用生成器的原因是为了避免这个问题,它应该确保你只获得未使用的ID。如果您不能在此处依赖,可以添加一个解决方法:
您可以先查询以查找表中的最大ID。如果生成器允许设置nextvalue然后更改它以便从那里开始,否则反复调用生成器直到你得到一个高于该最大值的键。
您可以编写一个获取现有行号的查询,并使用插入代码检查id是否在列表中(假设这是唯一要插入的内容)。
您可以在每次插入之前执行选择计数,以确保ID未使用。
重复使用先前删除的行所使用的ID,只是为了填补空白,可能会造成混淆,应该避免使用。没有多少好处,似乎很麻烦。如果您想要序列号,请为其添加特定字段。
您的异常处理无法区分不同类型的SQLExceptions。 并非所有SQLExceptions都来自约束违规;如果你的错误不与生成的密钥相关(例如让数据库关闭或填写事务日志),那么你的代码将无休止地循环。
您可以根据SQLState属性区分不同类型的SQLExceptions。 For Postgres, SqlStates starting with 23 refer to constraint issues
如果你想捕获约束异常,那么你应该检查sqlstate并重新抛出不匹配的异常,这样它们就会结束这个过程(因为出现了一些不可恢复的错误)。
对于扩展SQLTransientException的SQLExceptions,可能值得重试它们。这是唯一一种使用循环来实现这样的插入的唯一情况。
你的插入SQL似乎没有引用它的值,你在哪里连接一个没有单引号的值,所以结果不正确(除非你依赖单引号计算)作为传入字符串的一部分)。您最好使用PreparedStatements,它们不仅可以防止SQL注入,还可以为您处理参数值的引用,因此它们更不容易出错。
答案 1 :(得分:1)
如果您有相同的例外,您将拥有无限循环。
检查executeUpdate
可以抛出哪些异常,并使用适当的消息添加适当的catch块。
示例:
catch (PSQLException) {
System.out.println("The key is already exist");
isInserted=true;
}
catch (SQLException e) {
System.out.println(e);
isInserted=false;
}catch (SQLTimeoutException e) {
System.out.println(e);
isInserted=false;
}