简体   繁体   English

使用while循环进行异常处理

[英]Exception Handling using while loop

i am using postgreSql and Java , here is the error shown in eclipse console 我正在使用postgreSql和Java,这里是eclipse控制台中显示的错误

org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "km_rel_user_test_details_pkey",

Here the cause of the error is(i guess ) due to duplicate key present in database , I have written a while loop to handle this exception, i just want to know, whether this approach is correct and will work for every situation, any error found/ ask for improvement will be appreciated, thanks in advance, here is my java method. 这里错误的原因是(我猜)由于数据库中存在重复键,我已经写了一个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;
  }

The reason for using a generator is to avoid this problem, it's supposed to make sure you get only unused ids. 使用生成器的原因是为了避免这个问题,它应该确保你只获得未使用的ID。 If you can't rely on that here, you could add a workaround: 如果你不能在这里依赖它,你可以添加一个解决方法:

  • You could query first to find the maximum id in the table. 您可以先查询以查找表中的最大ID。 If the generator allows setting a nextvalue then change it so it starts from there, otherwise call the generator over and over until you get a key higher than that maximum. 如果生成器允许设置nextvalue然后更改它以便从那里开始,否则反复调用生成器直到你得到一个高于该最大值的键。

  • You could write a query that gets the existing row numbers and have insert code check that the id is not in the list (assumes this is the only thing doing inserts). 您可以编写一个获取现有行号的查询,并使用插入代码检查id不在列表中(假设这是唯一的插入操作)。

  • You could execute a select count before each insert to make sure the id is unused. 您可以在每次插入之前执行选择计数,以确保未使用该ID。

Reusing IDs used by previously-deleted rows, just so you can fill in the gaps, has the potential to cause confusion and should be avoided. 重复使用先前删除的行所使用的ID,以便填补空白,可能会造成混淆,应该避免使用。 It seems like a lot of trouble to go to with not much benefit. 没有多少好处,似乎很麻烦。 If you want sequential numbers then add a specific field for that. 如果您想要序列号,则为其添加特定字段。

Your exception-handling is not distinguishing between different kinds of SQLExceptions. 您的异常处理不区分不同类型的SQLExceptions。 Not all your SQLExceptions will be from constraint violations; 并非所有SQLExceptions都来自约束违规; if you have something go wrong that is not related to your generated key (such as having the database go down, or filling up the transaction log) then your code will loop endlessly. 如果你有什么事情出问题是相关的生成的密钥(如具有数据库下去,或填充事务日志),那么你的代码将无限循环。

You can distinguish between different kinds of SQLExceptions based on their SQLState property. 您可以根据SQLState属性区分不同类型的SQLExceptions。 For Postgres, SqlStates starting with 23 refer to constraint issues . 对于Postgres,从23开始的SqlStates引用约束问题

If you want to catch constraint exceptions then you should check the sqlstate and rethrow the exceptions that don't match, so that they will end the process (because something went wrong that is nonrecoverable). 如果你想捕获约束异常,那么你应该检查sqlstate并重新抛出不匹配的异常,这样它们就会结束进程(因为出现了一些不可恢复的错误)。

For SQLExceptions that extend SQLTransientException it might be worthwhile to retry them. 对于扩展SQLTransientException的SQLExceptions,可能值得重试它们。 That is about the only case where using a loop for inserts like this would be justified. 这是唯一的情况,使用这样的插入循环是合理的。

Your insert SQL does not seem to have its values quoted, where you are concatenating a value where are no single quotes surrounding it, so the result will not be correct (unless you're counting on single-quotes being included as part of the passed-in string). 您的插入SQL似乎没有引用其值,在这里您连接一个值,其中没有单引号围绕它,因此结果将不正确(除非您指望单引号作为传递的一部分包含在内) -in string)。 You'd be better off using PreparedStatements, they not only protect against SQL injection but also handle quoting of parameter values for you, so they are much less error-prone. 您最好使用PreparedStatements,它们不仅可以防止SQL注入,还可以为您处理参数值的引用,因此它们更不容易出错。

You will have endless loop if you have the same exception. 如果您有相同的异常,您将拥有无限循环。

check which exceptions can be thrown by executeUpdate and add the appropriate catch blocks with appropriate messages. 检查executeUpdate可以抛出哪些异常,并使用适当的消息添加适当的catch块。

Example: 例:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM