繁体   English   中英

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

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

我需要使用CSV数据更新表。 在更新发生之前,所有数据都经过验证:一种验证方法(以下未显示女巫)检查某些假设是否正确,并将对象“标记”为有效或无效。 我已经对其进行了很多测试,并且可以按照我想要的方式正常工作。

即使这样,我仍然保证即使批处理失败,所有语句都将被执行,这是我无法想到的。 如果发生这种情况,我希望跳过该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");
}

我看到了许多有关如何处理异常的资料,但没有任何资料说明或指导我如何重试下一个语句,即如何执行下一个批处理。

我如何做到这一点?

编辑:我正在使用PostgreSQL

我设法通过用trycatch语句包围批处理执行来重试下一批。 这样,我就可以捕获BatchUpdateException并调用continue语句。

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

} catch (BatchUpdateException e) {

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

continue;
}

我还使用了一些控制逻辑来“标记”已执行的语句和批处理并记录它们,从而使某些语句失败时的故障排除变得更加容易。

这是完整的代码:

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