修正重复导入的问题
This commit is contained in:
@@ -43,6 +43,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -70,6 +72,8 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
|
||||
private static final int DB_PROMOTER_NAME_MAX = 100;
|
||||
private static final int DB_DESC_MAX = 512;
|
||||
private static final int ID_IN_QUERY_BATCH = 500;
|
||||
/** 同一租户同时只允许一个 Excel 导入,避免并发请求或连点导致重复插入 */
|
||||
private static final ConcurrentHashMap<String, ReentrantLock> TENANT_LB_DAILY_TRADE_IMPORT_LOCKS = new ConcurrentHashMap<>();
|
||||
|
||||
@Autowired
|
||||
private ILbDailyUserTradeReportService lbDailyUserTradeReportService;
|
||||
@@ -197,6 +201,13 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
|
||||
return result;
|
||||
}
|
||||
|
||||
ReentrantLock tenantImportLock = TENANT_LB_DAILY_TRADE_IMPORT_LOCKS.computeIfAbsent(
|
||||
normalizedTenantId, k -> new ReentrantLock());
|
||||
if (!tenantImportLock.tryLock()) {
|
||||
result.put("success", false);
|
||||
result.put("message", "该租户已有导入任务正在执行,请等待完成后再试,避免重复写入数据");
|
||||
return result;
|
||||
}
|
||||
String previousTenantId = TenantContextHolder.getTenantId();
|
||||
TenantContextHolder.setTenantId(normalizedTenantId);
|
||||
try {
|
||||
@@ -223,6 +234,8 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
|
||||
List<LbDailyUserTrade> importList = new ArrayList<>();
|
||||
List<String> skippedRows = new ArrayList<>();
|
||||
int skippedHiddenRows = 0;
|
||||
/** 表头以下:非空行且非隐藏行,即参与解析的 Excel 行数(含解析失败/跳过的行) */
|
||||
int excelTableRowCount = 0;
|
||||
DataFormatter dataFormatter = new DataFormatter();
|
||||
log.info("开始导入Excel,fileName={}, size={} bytes, defaultReportDate={}",
|
||||
originalFilename, file.getSize(), defaultReportDate);
|
||||
@@ -247,12 +260,12 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
|
||||
if (row == null || isEmptyRow(row, dataFormatter)) {
|
||||
continue;
|
||||
}
|
||||
// 隐藏行(行高为 0)在部分导出/复制模板中会与可见行重复存一份数据;
|
||||
// POI 仍会遍历到这些行,若不跳过会导致导入条数约为可见行的整数倍。
|
||||
// 部分导出模板会把同一笔数据再存一份「行高为 0」的隐藏行;与业务是否重复无关,仅排除此类重复物理行。
|
||||
if (row.getZeroHeight()) {
|
||||
skippedHiddenRows++;
|
||||
continue;
|
||||
}
|
||||
excelTableRowCount++;
|
||||
try {
|
||||
LbDailyUserTrade trade = parseTradeRow(row, headerIndexMap, dataFormatter, fallbackReportDate, normalizedTenantId);
|
||||
if (trade == null) {
|
||||
@@ -327,9 +340,12 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
|
||||
result.put("parsedCount", total);
|
||||
result.put("skipCount", skippedRows.size());
|
||||
result.put("skippedRows", skippedRows);
|
||||
result.put("skippedHiddenRowCount", skippedHiddenRows);
|
||||
return result;
|
||||
}
|
||||
|
||||
int dbInsertedRowCount = importList.size();
|
||||
log.info("lb_daily_user_trade 导入落库完成:Excel表格行数={},插入数据库行数={}", excelTableRowCount, dbInsertedRowCount);
|
||||
log.info("导入成功,fileName={}, importCount={}, skipCount={}, skippedHiddenRows={}",
|
||||
originalFilename, importList.size(), skippedRows.size(), skippedHiddenRows);
|
||||
result.put("success", true);
|
||||
@@ -345,6 +361,7 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
|
||||
} else {
|
||||
TenantContextHolder.clear();
|
||||
}
|
||||
tenantImportLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,13 +533,7 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
|
||||
return null;
|
||||
}
|
||||
|
||||
LbDailyUserTrade matchedTrade = null;
|
||||
if (StringUtils.isBlank(userId) && StringUtils.isNotBlank(nickname)) {
|
||||
matchedTrade = findLatestTradeByNickname(tenantId, nickname);
|
||||
if (matchedTrade != null && StringUtils.isNotBlank(matchedTrade.getUserId())) {
|
||||
userId = matchedTrade.getUserId();
|
||||
}
|
||||
}
|
||||
// 严格按 Excel 行写入:不查库合并/补全 userId 或推广人;与库内是否重复无关,每行一条 INSERT。
|
||||
if (userId.isEmpty()) {
|
||||
userId = "AUTO_USERID_" + UUID.randomUUID().toString().replace("-", "");
|
||||
}
|
||||
@@ -534,18 +545,8 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
|
||||
trade.setNickname(nickname);
|
||||
trade.setDailySellAmt(readDecimal(row, headerMap.get("dailySellAmt"), formatter));
|
||||
trade.setDailyBuyAmt(readDecimal(row, headerMap.get("dailyBuyAmt"), formatter));
|
||||
String promoterId = readString(row, headerMap.get("promoterId"), formatter);
|
||||
String promoterName = readString(row, headerMap.get("promoterName"), formatter);
|
||||
if (matchedTrade != null) {
|
||||
if (StringUtils.isBlank(promoterId) && StringUtils.isNotBlank(matchedTrade.getPromoterId())) {
|
||||
promoterId = matchedTrade.getPromoterId();
|
||||
}
|
||||
if (StringUtils.isBlank(promoterName) && StringUtils.isNotBlank(matchedTrade.getPromoterName())) {
|
||||
promoterName = matchedTrade.getPromoterName();
|
||||
}
|
||||
}
|
||||
trade.setPromoterId(promoterId);
|
||||
trade.setPromoterName(promoterName);
|
||||
trade.setPromoterId(readString(row, headerMap.get("promoterId"), formatter));
|
||||
trade.setPromoterName(readString(row, headerMap.get("promoterName"), formatter));
|
||||
trade.setDescContent(readString(row, headerMap.get("descContent"), formatter));
|
||||
|
||||
BigDecimal sell = trade.getDailySellAmt() == null ? BigDecimal.ZERO : trade.getDailySellAmt();
|
||||
@@ -562,15 +563,6 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
|
||||
return trade;
|
||||
}
|
||||
|
||||
private LbDailyUserTrade findLatestTradeByNickname(String tenantId, String nickname) {
|
||||
LambdaQueryWrapper<LbDailyUserTrade> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(LbDailyUserTrade::getTenantId, tenantId)
|
||||
.eq(LbDailyUserTrade::getNickname, nickname.trim())
|
||||
.orderByDesc(LbDailyUserTrade::getUpdatedAt)
|
||||
.last("limit 1");
|
||||
return this.getOne(wrapper, false);
|
||||
}
|
||||
|
||||
private boolean isEmptyRow(Row row, DataFormatter formatter) {
|
||||
if (row == null) {
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user