使用while循环进行异常处理

时间:2014-09-17 14:12:27

标签: java sql postgresql jdbc exception-handling

我正在使用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;
  }

2 个答案:

答案 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;
    }