From 3d06caa2a10411587d971f38e5dc8f5bccc814e6 Mon Sep 17 00:00:00 2001 From: ni ziyi <310925901@qq.com> Date: Fri, 23 Jan 2026 21:42:53 +0800 Subject: [PATCH] =?UTF-8?q?=E9=81=BF=E5=85=8D=E5=B9=B6=E5=8F=91=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../accounting/config/SchedulerConfig.java | 26 +++++++++- .../accounting/mapper/GoldPriceMapper.java | 9 ++++ .../service/impl/GoldPriceServiceImpl.java | 50 +++++++++++++++---- 3 files changed, 75 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/accounting/config/SchedulerConfig.java b/src/main/java/com/accounting/config/SchedulerConfig.java index 1ff4616..796d41c 100644 --- a/src/main/java/com/accounting/config/SchedulerConfig.java +++ b/src/main/java/com/accounting/config/SchedulerConfig.java @@ -1,10 +1,34 @@ package com.accounting.config; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.lang.NonNull; 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 @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; + }); + } } diff --git a/src/main/java/com/accounting/mapper/GoldPriceMapper.java b/src/main/java/com/accounting/mapper/GoldPriceMapper.java index 96aa8c5..2c99ada 100644 --- a/src/main/java/com/accounting/mapper/GoldPriceMapper.java +++ b/src/main/java/com/accounting/mapper/GoldPriceMapper.java @@ -20,4 +20,13 @@ public interface GoldPriceMapper extends BaseMapper { @Select("SELECT MAX(price_date) FROM gold_price WHERE gold_id = #{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); } diff --git a/src/main/java/com/accounting/service/impl/GoldPriceServiceImpl.java b/src/main/java/com/accounting/service/impl/GoldPriceServiceImpl.java index 6e11cfa..53cd48a 100644 --- a/src/main/java/com/accounting/service/impl/GoldPriceServiceImpl.java +++ b/src/main/java/com/accounting/service/impl/GoldPriceServiceImpl.java @@ -18,7 +18,6 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; -import java.util.UUID; import java.util.stream.Collectors; @Slf4j @@ -51,6 +50,8 @@ public class GoldPriceServiceImpl implements GoldPriceService { @Override @Transactional public void refreshCurrentPrice(String goldId) { + log.info("Starting refreshCurrentPrice for goldId={}", goldId); + K780Response response = k780ApiClient.fetchGoldPrice(goldId); if (!"1".equals(response.getSuccess()) || response.getResult() == null) { @@ -58,14 +59,39 @@ public class GoldPriceServiceImpl implements GoldPriceService { } 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); + log.info("Extracted gold price data - goldId: {}, uptime: {}, lastPrice: {}", + goldPriceData.getGoldId(), goldPriceData.getUptime(), goldPriceData.getLastPrice()); + 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分钟查询一次结果并存储 goldPrice.setCreateTime(LocalDateTime.now()); 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 @@ -137,16 +163,22 @@ public class GoldPriceServiceImpl implements GoldPriceService { // 解析更新时间 if (data.getUptime() != null && !data.getUptime().isEmpty()) { try { - entity.setUpdateTime(LocalDateTime.parse(data.getUptime(), DATE_TIME_FORMATTER)); - entity.setPriceDate(entity.getUpdateTime().toLocalDate()); + LocalDateTime parsedTime = LocalDateTime.parse(data.getUptime(), DATE_TIME_FORMATTER); + entity.setUpdateTime(parsedTime); + entity.setPriceDate(parsedTime.toLocalDate()); + log.debug("Successfully parsed update time: {} -> {}", data.getUptime(), parsedTime); } catch (Exception e) { - log.warn("Failed to parse update time: {}", data.getUptime()); - entity.setUpdateTime(LocalDateTime.now()); - entity.setPriceDate(LocalDate.now()); + log.warn("Failed to parse update time: {}, error: {}, using current time instead", + data.getUptime(), e.getMessage()); + LocalDateTime now = LocalDateTime.now(); + entity.setUpdateTime(now); + entity.setPriceDate(now.toLocalDate()); } } else { - entity.setUpdateTime(LocalDateTime.now()); - entity.setPriceDate(LocalDate.now()); + log.warn("Uptime is null or empty, using current time"); + LocalDateTime now = LocalDateTime.now(); + entity.setUpdateTime(now); + entity.setPriceDate(now.toLocalDate()); } return entity;