You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中基于日期字段查询SQL汇率数据的正确方法及日期转换

问题解析与解决方案

问题背景

我创建了包含date(日期)和rate(货币汇率)字段的EmployeeExchangeRate实体,想要编写服务层方法,通过日、月、年参数查询对应日期的汇率数据。目前已完成实体类、Repository和服务层方法的编写,但日期字符串解析失败,代码无法正常运行。需要解决两个问题:

  1. 基于日期查询SQL数据的正确方式
  2. 如何将日、月、年参数转换为匹配数据库存储的日期格式

现有代码

实体类

@Entity
@Getter
@Setter
@Table(name = "ExchangeRate")
public class EmployeeExchangeRate extends BaseEntity {

    @Basic
    @Temporal(TemporalType.DATE)
    @Column(name = "date", nullable = false)
    private Date date;

    @Column(name = "rate", nullable = false)
    private double rate;

}

Repository

public interface EmployeeExchangeRateRepository extends JpaRepository<EmployeeExchangeRate, Long> {
    EmployeeExchangeRate findByDate(Date date);
}

存在问题的服务层方法

private void findRate(int day, int month, int year){

    String s = day + "-" + month + "-" + year;

    Optional<EmployeeExchangeRate> foundExchangeRate =
            exchangeRateRepository.findByDate(new SimpleDateFormat("yyyy/dd/MM").parse(s));

    System.out.println(foundExchangeRate.get());
}

核心问题分析

代码解析失败的直接原因:

  • 拼接出的字符串格式是日-月-年(比如15-08-2024),但用SimpleDateFormat("yyyy/dd/MM")去解析,格式完全不匹配,触发ParseException。
  • SimpleDateFormat是线程不安全类,直接使用存在并发风险。
  • 直接调用Optional.get()会在数据不存在时抛出空指针异常。

解决方案

方案一:使用Java 8+ LocalDate(推荐)

JPA 2.2及以上原生支持java.time包下的日期类,这是目前最规范的做法:

  1. 修改实体类日期字段
@Entity
@Getter
@Setter
@Table(name = "ExchangeRate")
public class EmployeeExchangeRate extends BaseEntity {

    // 替换为LocalDate,无需@Temporal注解
    @Column(name = "date", nullable = false)
    private LocalDate date;

    @Column(name = "rate", nullable = false)
    private double rate;

}
  1. 更新Repository方法
public interface EmployeeExchangeRateRepository extends JpaRepository<EmployeeExchangeRate, Long> {
    // 返回Optional避免空指针
    Optional<EmployeeExchangeRate> findByDate(LocalDate date);
}
  1. 重构服务层方法
    直接用LocalDate.of构造日期,无需字符串拼接,完全避免解析错误:
private void findRate(int day, int month, int year) {
    LocalDate targetDate = LocalDate.of(year, month, day);
    Optional<EmployeeExchangeRate> foundExchangeRate = exchangeRateRepository.findByDate(targetDate);
    
    // 安全处理Optional结果
    foundExchangeRate.ifPresentOrElse(
        exchangeRate -> System.out.println(exchangeRate),
        () -> System.out.println("未找到对应日期的汇率数据")
    );
}

方案二:兼容旧版Java(使用java.util.Date)

如果必须使用Date类型,修复解析逻辑即可:

private void findRate(int day, int month, int year) {
    // 按目标格式拼接字符串:yyyy/dd/MM
    String dateStr = String.format("%d/%02d/%02d", year, day, month);
    try {
        // 用匹配的格式解析字符串
        Date targetDate = new SimpleDateFormat("yyyy/dd/MM").parse(dateStr);
        EmployeeExchangeRate foundExchangeRate = exchangeRateRepository.findByDate(targetDate);
        
        if (foundExchangeRate != null) {
            System.out.println(foundExchangeRate);
        } else {
            System.out.println("未找到对应日期的汇率数据");
        }
    } catch (ParseException e) {
        e.printStackTrace();
        // 这里可以添加异常处理逻辑,比如返回错误提示
    }
}

注意:SimpleDateFormat线程不安全,如果是在多线程环境下使用,建议每次创建新实例,或者用ThreadLocal包装来保证线程安全。


关于MySQL日期存储的说明

MySQL的DATE类型默认以YYYY-MM-DD格式存储,但JPA会自动处理实体类日期类型与数据库存储格式的转换,你不需要手动将日期转换为yyyy/dd/mm格式存入数据库。只要实体类字段与数据库字段映射正确,查询时传入正确的日期对象,JPA会自动生成匹配的SQL查询语句。

内容的提问来源于stack exchange,提问作者GiviXbo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 09:30:24