Don’t say much, just go to the code.
/**
* 对大型数据列表进行分批处理,并在每批数据上执行事务性处理
*
* @param sortedList 已排序的数据列表,确保批处理的顺序性,减少死锁风险
* @param batchSize 每批处理的数据量大小
* @param batchProcessorWithTransaction 用于处理每一批次数据并执行事务的函数,接收当前批次数据和重试次数
* @author bood
* @since 2024/01/23
*/
public <T> void batchProcessOptimized(List<T> sortedList, int batchSize,
BiConsumer<List<T>, Integer> batchProcessorWithTransaction) {
int startIdx = 0;
while (startIdx < sortedList.size()) {
int endIdx = Math.min(sortedList.size(), startIdx + batchSize);
List<T> batch = sortedList.subList(startIdx, endIdx);
boolean isProcessedSuccessfully = false;
int retryCount = 0;
while (!isProcessedSuccessfully && retryCount < 3) {
try {
batchProcessorWithTransaction.accept(batch, retryCount);
isProcessedSuccessfully = true;
} catch (DataAccessException ex) {
if (isDeadlockException(ex)) {
retryCount++;
waitForRetry(retryCount);
} else {
throw ex;
}
}
}
startIdx = endIdx;
}
}
/**
* 检查是否因为数据库死锁导致的异常
*
* @param ex 异常对象
* @return boolean
* @author bood
* @since 2024/01/23
*/
private boolean isDeadlockException(DataAccessException ex) {
Throwable cause = ex.getCause();
return cause instanceof SQLException && "40001".equals(((SQLException) cause).getSQLState());
}
/**
* 根据重试次数进行等待,采用指数退避策略减少连续死锁的可能性
*
* @param retryCount 当前重试次数
* @author bood
* @since 2024/01/23
*/
private void waitForRetry(int retryCount) {
try {
long waitTimeMillis = (long) (Math.pow(2, retryCount) * 100);
Thread.sleep(waitTimeMillis);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}