Java 批处理执行失败后,如何重试未执行的语句?
我需要用CSV中的数据更新表。所有数据在更新发生之前都经过验证:验证方法(以下未显示)检查某些假设是否正确,并将对象“标记”为有效或无效。我已经对它进行了很多测试,它的工作完全符合我的要求 即便如此,我还是要保证,即使批处理失败,所有语句都会被执行,这是我无法想象的。如果发生这种情况,我希望跳过该fail语句中的批处理,并执行下一个批处理Java 批处理执行失败后,如何重试未执行的语句?,java,postgresql,prepared-statement,Java,Postgresql,Prepared Statement,我需要用CSV中的数据更新表。所有数据在更新发生之前都经过验证:验证方法(以下未显示)检查某些假设是否正确,并将对象“标记”为有效或无效。我已经对它进行了很多测试,它的工作完全符合我的要求 即便如此,我还是要保证,即使批处理失败,所有语句都会被执行,这是我无法想象的。如果发生这种情况,我希望跳过该fail语句中的批处理,并执行下一个批处理 public void updateTable(List<PersonBean> personList) { Connection co
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");
}
public void updateTable(列表个人列表){
连接=空;
PreparedStatement ps=null;
String updateDBPersonSQL=“更新人员集合并\u父项\u id=?其中id=?”;
试一试{
logger.info(“数据更新已启动”);
输入=新文件输入流(“资源/属性文件/应用程序.properties”);
属性。加载(输入);
final int batchSize=Integer.parseInt(properties.getProperty(“batchSize”);
connection=DBConnection.getConnection();
connection.setAutoCommit(false);
int-validObj=0;
ps=connection.prepareStatement(updateDBPersonSQL);
对于(int i=0;i=0){
info(updateCount.length+“objects updated.”);
}else if(updateCount[i]==语句。执行\u失败){
?????
}
}
logger.error(updateCount.length);
logger.error(“BatchUpdateException:+e”);
logger.error(“getNextException:+e.getNextException());
试一试{
connection.rollback();
}捕获(SQLException e1){
logger.error(“回滚错误:+e1,e1”);
}
}最后{
如果(ps!=null){
试一试{
ps.close();
}捕获(SQLE异常){
logger.info(e);
}
}
}
logger.info(“数据更新完成”);
}
我看到了很多关于如何处理异常的资料,但没有任何资料向我解释或指出如何重试下一个语句,这意味着如何执行下一批
我如何做到这一点
编辑:我正在使用Postgresql我通过使用
try
和catch
语句围绕批处理执行来尝试下一批处理。这样我就能够捕获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");
public void updateTable(List personList)引发异常{
logger.info(“表更新已启动”);
List personListValidated=CreateValidsMTList(personList);
连接=空;
PreparedStatement ps=null;
String updatePersonSQL=“更新人员集合并\u父项\u id=?其中id=?”;
输入=新文件输入流(“资源/属性文件/应用程序.properties”);
属性。加载(输入);
final int batchSize=Integer.parseInt(properties.getProperty(“batchSize”);
/*一个列表用于“标记”已执行的批。BatchStatus OBJ只有两个参数,编号(随着批的执行而递增)和状态(成功或失败)*/
List batchStatusList=新建ArrayList();
/*此变量将用于帮助标记已执行的批处理和语句*/
int batchCount=0;
int stmtadedtobatchcount=0;
试一试{
connection=DBConnection.getConnection();
connection.setAutoCommit(false);
ps=connection.prepareStatement(updatePersonSQL);
/*personListValidated包含将在表中更新的对象
*这一部分在其他两种方法中进行了介绍,使添加到批处理中的语句更易于控制。
*/
对于(int i=0;i