避免并发问题

This commit is contained in:
ni ziyi 2026-01-23 21:42:53 +08:00
parent c765ffaa89
commit 3d06caa2a1
3 changed files with 75 additions and 10 deletions

View File

@ -1,10 +1,34 @@
package com.accounting.config; package com.accounting.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.lang.NonNull;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@Configuration @Configuration
@EnableScheduling @EnableScheduling
public class SchedulerConfig { public class SchedulerConfig implements SchedulingConfigurer {
/**
* 配置定时任务为单线程执行避免并发问题
*/
@Override
public void configureTasks(@NonNull ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
@Bean(destroyMethod = "shutdown")
public Executor taskExecutor() {
return Executors.newSingleThreadScheduledExecutor(r -> {
Thread thread = new Thread(r, "gold-price-scheduler");
thread.setDaemon(true);
return thread;
});
}
} }

View File

@ -20,4 +20,13 @@ public interface GoldPriceMapper extends BaseMapper<GoldPrice> {
@Select("SELECT MAX(price_date) FROM gold_price WHERE gold_id = #{goldId}") @Select("SELECT MAX(price_date) FROM gold_price WHERE gold_id = #{goldId}")
LocalDate selectLatestDate(@Param("goldId") String goldId); LocalDate selectLatestDate(@Param("goldId") String goldId);
/**
* 检查指定时间点是否已存在数据用于防重复插入
* @param goldId 黄金品种ID
* @param updateTime 更新时间
* @return 存在的记录数
*/
@Select("SELECT COUNT(*) FROM gold_price WHERE gold_id = #{goldId} AND update_time = #{updateTime}")
int countByGoldIdAndUpdateTime(@Param("goldId") String goldId, @Param("updateTime") java.time.LocalDateTime updateTime);
} }

View File

@ -18,7 +18,6 @@ import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Slf4j @Slf4j
@ -51,6 +50,8 @@ public class GoldPriceServiceImpl implements GoldPriceService {
@Override @Override
@Transactional @Transactional
public void refreshCurrentPrice(String goldId) { public void refreshCurrentPrice(String goldId) {
log.info("Starting refreshCurrentPrice for goldId={}", goldId);
K780Response response = k780ApiClient.fetchGoldPrice(goldId); K780Response response = k780ApiClient.fetchGoldPrice(goldId);
if (!"1".equals(response.getSuccess()) || response.getResult() == null) { if (!"1".equals(response.getSuccess()) || response.getResult() == null) {
@ -58,14 +59,39 @@ public class GoldPriceServiceImpl implements GoldPriceService {
} }
K780Result result = response.getResult(); K780Result result = response.getResult();
// 记录API返回的所有数据用于调试
if (result.getDtList() != null) {
log.info("API returned {} gold price records", result.getDtList().size());
result.getDtList().forEach((id, data) -> {
log.info("Gold price data - goldId: {}, uptime: {}, lastPrice: {}",
id, data.getUptime(), data.getLastPrice());
});
}
K780Result.GoldPriceData goldPriceData = extractGoldPriceData(result, goldId); K780Result.GoldPriceData goldPriceData = extractGoldPriceData(result, goldId);
log.info("Extracted gold price data - goldId: {}, uptime: {}, lastPrice: {}",
goldPriceData.getGoldId(), goldPriceData.getUptime(), goldPriceData.getLastPrice());
GoldPrice goldPrice = convertToEntity(goldPriceData); GoldPrice goldPrice = convertToEntity(goldPriceData);
log.info("Converted to entity - goldId: {}, updateTime: {}, priceDate: {}",
goldPrice.getGoldId(), goldPrice.getUpdateTime(), goldPrice.getPriceDate());
// 防重复插入检查是否已存在相同时间点的数据
int existingCount = goldPriceMapper.countByGoldIdAndUpdateTime(goldId, goldPrice.getUpdateTime());
if (existingCount > 0) {
log.warn("Gold price data already exists for goldId={}, updateTime={}, skipping insert",
goldId, goldPrice.getUpdateTime());
return;
}
// 插入新记录 每15分钟查询一次结果并存储 // 插入新记录 每15分钟查询一次结果并存储
goldPrice.setCreateTime(LocalDateTime.now()); goldPrice.setCreateTime(LocalDateTime.now());
goldPriceMapper.insert(goldPrice); goldPriceMapper.insert(goldPrice);
log.info("Refreshed gold price for goldId={}, priceDate={}", goldPrice.getGoldId(), goldPrice.getPriceDate()); log.info("Successfully inserted gold price - id: {}, goldId: {}, priceDate: {}, updateTime: {}, createTime: {}",
goldPrice.getId(), goldPrice.getGoldId(), goldPrice.getPriceDate(),
goldPrice.getUpdateTime(), goldPrice.getCreateTime());
} }
@Override @Override
@ -137,16 +163,22 @@ public class GoldPriceServiceImpl implements GoldPriceService {
// 解析更新时间 // 解析更新时间
if (data.getUptime() != null && !data.getUptime().isEmpty()) { if (data.getUptime() != null && !data.getUptime().isEmpty()) {
try { try {
entity.setUpdateTime(LocalDateTime.parse(data.getUptime(), DATE_TIME_FORMATTER)); LocalDateTime parsedTime = LocalDateTime.parse(data.getUptime(), DATE_TIME_FORMATTER);
entity.setPriceDate(entity.getUpdateTime().toLocalDate()); entity.setUpdateTime(parsedTime);
entity.setPriceDate(parsedTime.toLocalDate());
log.debug("Successfully parsed update time: {} -> {}", data.getUptime(), parsedTime);
} catch (Exception e) { } catch (Exception e) {
log.warn("Failed to parse update time: {}", data.getUptime()); log.warn("Failed to parse update time: {}, error: {}, using current time instead",
entity.setUpdateTime(LocalDateTime.now()); data.getUptime(), e.getMessage());
entity.setPriceDate(LocalDate.now()); LocalDateTime now = LocalDateTime.now();
entity.setUpdateTime(now);
entity.setPriceDate(now.toLocalDate());
} }
} else { } else {
entity.setUpdateTime(LocalDateTime.now()); log.warn("Uptime is null or empty, using current time");
entity.setPriceDate(LocalDate.now()); LocalDateTime now = LocalDateTime.now();
entity.setUpdateTime(now);
entity.setPriceDate(now.toLocalDate());
} }
return entity; return entity;