简体   繁体   English

批处理执行失败后,如何重试未执行的语句?

[英]How can I retry the statements that were not executed after a batch execution fails?

I'm need to update a table with data from a CSV. 我需要使用CSV数据更新表。 All data is validated before the update takes place: a validation method (witch is not presented bellow) checks if some assumptions are true and "flags" the object as valid or invalid. 在更新发生之前,所有数据都经过验证:一种验证方法(以下未显示女巫)检查某些假设是否正确,并将对象“标记”为有效或无效。 I've already test it a lot and it's working exactly as I want. 我已经对其进行了很多测试,并且可以按照我想要的方式正常工作。

Even so, I would like to guarantee that all Statements will be executed even if there's a fail on a batch, something that I was not able to think about. 即使这样,我仍然保证即使批处理失败,所有语句都将被执行,这是我无法想到的。 If this happens, I want the batch in witch this fail statement is to be skipped and that the next one is executed. 如果发生这种情况,我希望跳过该fail语句中的批处理,并执行下一个语句。

public void updateTable(List<PersonBean> personList) {

    Connection connection = null;
    PreparedStatement ps = null;

    String updateDBPersonSQL = "UPDATE Person set merge_parent_id = ? WHERE id = ?";

    try {
        logger.info("DATA UPDATING STARTED");

        input = new FileInputStream("resources/propertiesFiles/applications.properties");
        properties.load(input);

        final int batchSize = Integer.parseInt(properties.getProperty("batchSize"));

        connection = DBConnection.getConnection();
        connection.setAutoCommit(false);

        int validObj = 0;

        ps = connection.prepareStatement(updateDBPersonSQL);

        for (int i = 0; i < personList.size(); i++) {

            PersonBean person = personList.get(i);

            if (person.getValidationStatus().equals("valid")) {

                ps.setInt(1, person.getMerge_parent_id());
                ps.setInt(2, person.getId());
                ps.addBatch();

                validObj++;

                if (validObj % batchSize == 0 && validObj != 0) {
                    ps.executeBatch();
                    connection.commit();

                    logger.info((batchSize) + " rows updated");
                } 
            }
        }
        int [] batchCount = ps.executeBatch();
        connection.commit();

        logger.info(batchCount.length + " rows updated");

        writeValidationStatusToCSV(personList);

    } catch (BatchUpdateException e) {
        int [] updateCount = e.getUpdateCounts();

            for (int i = 0; i < updateCount.length; i++) {

                if (updateCount[i] >= 0) {

                    logger.info(updateCount.length + " objects updated.");

                } else if (updateCount[i] == Statement.EXECUTE_FAILED) {

                    ?????
                }
            }
        logger.error(updateCount.length);
        logger.error("BatchUpdateException: " + e);
        logger.error("getNextException: " + e.getNextException());

        try {
            connection.rollback();
        } catch (SQLException e1) {
            logger.error("Rollback error: " + e1, e1);
        }
    } finally {
        if (ps!= null) {
            try {
                ps.close();
            } catch (SQLException e) {
                logger.info(e);
            }
        }
    }
    logger.info("DATA UPDATING FINISHED");
}

I saw a lot of material about how to handle the exception, but none explained or pointed me to the direction of how to retry the next Statements, it means, how to execute the next batch. 我看到了许多有关如何处理异常的资料,但没有任何资料说明或指导我如何重试下一个语句,即如何执行下一个批处理。

How do I manage to do this? 我如何做到这一点?

EDIT: I'm using Postgresql 编辑:我正在使用PostgreSQL

I manage to retry the next batches by surrounding the batch execution with try and catch statements. 我设法通过用trycatch语句包围批处理执行来重试下一批。 This way I'm able to catch the BatchUpdateException and call a continue statement. 这样,我就可以捕获BatchUpdateException并调用continue语句。

try {
ps.executeBatch();
connection.commit();
/*Some more code*/

} catch (BatchUpdateException e) {

connection.rollback();
/*Some more code*/

continue;
}

I also used some control logic to "flag" the statements and batches that were already executed and logged them, making it easier to troubleshoot if some statement fails. 我还使用了一些控制逻辑来“标记”已执行的语句和批处理并记录它们,从而使某些语句失败时的故障排除变得更加容易。

Here is the full code: 这是完整的代码:

public void updateTable(List<PersonBean> personList) throws Exception {

logger.info("TABLE UPDATE STARTED");

List <PersonBean> personListValidated = createValidStmtList(personList);

Connection connection = null;
PreparedStatement ps = null;

String updatePersonSQL = "UPDATE Person SET merge_parent_id = ? WHERE id = ?";

input = new FileInputStream("resources/propertiesFiles/applications.properties");
properties.load(input);

final int batchSize = Integer.parseInt(properties.getProperty("batchSize"));

/*A list was used to "flag" the batches that were already executed. BatchStatus objs have only two parameters, number (incremented as the batches are being executed) and status (success or fail).*/
List <BatchStatus> batchStatusList = new ArrayList<BatchStatus>();

 /*This variables will be used to help flag the batches and statements that were already executed.*/
int batchCount = 0;
int stmtAddedToBatchCount = 0;

try {
    connection = DBConnection.getConnection();
    connection.setAutoCommit(false);

    ps = connection.prepareStatement(updatePersonSQL);

    /*personListValidated contains the objects that will be updated in the table. Instead of doing the validation on the update method, I decomposed
     * this part in other 2 methods, making it easier to control of the statements added to the batch.
     */
    for (int i = 0; i < personListValidated.size(); i++) {

        PersonBean personValid = personListValidated.get(i);

        ps.setInt(1, personValid.getMerge_parent_id());
        ps.setInt(2, personValid.getId());
        ps.addBatch();

        personValid.setToBatch("true");

        stmtAddedToBatchCount++;

        logger.info("Row added to batch (count: " + stmtAddedToBatchCount + ")");

        if (stmtAddedToBatchCount % batchSize == 0) {
            batchCount++;

            try {
                ps.executeBatch();
                connection.commit();

                for (int j = stmtAddedToBatchCount - batchSize; j < stmtAddedToBatchCount; j++){

                    personValid = personListValidated.get(j);
                    personValid.setValidationStatus("success");
                }

                BatchStatus batchStatusObj = new BatchStatus(batchCount, "sucess");
                batchStatusList.add(batchStatusObj);   

                logger.info(batchStatusList.get(batchCount - 1));

            } catch (BatchUpdateException e) {

                connection.rollback();

                for (int j = stmtAddedToBatchCount - batchSize; j < stmtAddedToBatchCount; j++){

                    personValid = personListValidated.get(j);
                    personValid.setValidationStatus("fail");
                }

                BatchStatus batchStatusObj = new BatchStatus(batchCount, "fail");
                batchStatusList.add(batchStatusObj);

                logger.info(batchStatusList.get(batchCount - 1));
                logger.error("Bacth execution fail: " + e, e);

                continue;
            }
        }
    }

} catch (SQLException e) {
    logger.error(e, e);
}
int[] lastBatchCount = null;

/*Try and catch to handle the statements executed on the last batch*/
try {
    lastBatchCount = ps.executeBatch();
    connection.commit();

    for (int j = batchStatusList.size() * batchSize; j < stmtAddedToBatchCount; j++){

        PersonBean personValid = personListValidated.get(j);
        personValid.setValidationStatus("success");
    }

    logger.info(lastBatchCount.length + " rows inserted on the last batch");
    logger.info("Last batch excuted");

} catch (BatchUpdateException e) {

    connection.rollback();

    for (int j = batchStatusList.size() * batchSize; j < stmtAddedToBatchCount; j++){

        PersonBean personValid = personListValidated.get(j);
        personValid.setValidationStatus("fail");
    }

    logger.error("Last batch fail to execute: " + e, e);
}
writeValidationStatusToCSV(personList);

logger.info("TABLE UPDATE FINISHED");

} }

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

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