Java 使用while循环处理异常

Java 使用while循环处理异常,java,sql,postgresql,jdbc,exception-handling,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循环来处理这个异常,我只是想知道,这个方法是否正确,是否适用于所有情况,如果发现任何错误/要

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

如果您有相同的异常,您将有无止境的循环

检查
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;
    }

使用生成器的原因是为了避免这个问题,它应该确保您只获得未使用的ID。如果您不能在此处依赖此功能,您可以添加一个变通方法:

  • 您可以先查询以查找表中的最大id。如果生成器允许设置下一个值,则将其更改为从那里开始,否则反复调用生成器,直到获得高于该最大值的密钥

  • 您可以编写一个查询来获取现有的行号,并让插入代码检查id是否不在列表中(假设这是执行插入的唯一操作)

  • 您可以在每次插入之前执行select计数,以确保id未被使用

重用以前删除的行所使用的ID,只是为了填补空白,有可能导致混淆,应该避免。这似乎是一件麻烦事,却没有多少好处。如果您需要序列号,请为此添加一个特定字段

异常处理不会区分不同类型的SQLException。 并不是所有SQLException都来自约束冲突;如果出现与生成的密钥无关的错误(例如数据库关闭或事务日志填充),那么代码将无休止地循环

您可以根据SQLState属性区分不同类型的SQLException

如果您想捕获约束异常,那么您应该检查sqlstate并重新显示不匹配的异常,以便它们结束该过程(因为出现了不可恢复的错误)

对于扩展SQLTransientException的SQLException,可能值得重试。这大概是唯一一种对这样的插入使用循环的情况


您的insert SQL似乎没有引用其值,您连接的值周围没有单引号,因此结果将不正确(除非您将单引号作为传入字符串的一部分)。您最好使用PreparedStatements,它们不仅可以防止SQL注入,还可以为您处理参数值的引用,因此更不容易出错。

正确的方法是检查
getNextVal
返回重复键值的原因。我在谷歌上搜索过,但序列生成的代码和所有内容都是正确的,donno y它不工作。
getNextVal
做什么?它是一个序列生成器,生成下一个id,就像mysql中的autoincrement一样。+1用于使用
PreparedStatement
,我想补充一点,除非您确定需要它的线程安全(同步)功能,否则您应该避免使用
StringBuffer
行为。@NoData:像这样使用StringBuffer是很奇怪的,但由于无竞争的同步并不太昂贵(尤其是与jdbc开销相比),它似乎相对不重要。伙计们,我们公司有自己的框架(有点类似于struts 1.3),而且这个项目已经有10多年的历史了,ExecuteUpdate只将StringBuffer作为参数,我无法避免StringBuffer