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