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

如何在Spring Boot与Java中实现JSON到SQL列的映射并写入MySQL

问题描述

JSON数据结构

{
    "basecurrency": "USD",
    "data_date": "2022-07-25",
    "data": {
        "AED": 3.671159,
        "AFN": 89.81064,
        "ALL": 114.523046,
        "AMD": 409.987398,
        "ANG": 1.799784,
        // 另有100+货币汇率字段
    }
}

MySQL表结构

create table tblData(
   ID INT NOT NULL AUTO_INCREMENT,
   base_currency varchar(10) NOT NULL,
   data_date DATE NOT NULL,
   AED REAL(16,10) NOT NULL,
   AFN REAL(16,10) NOT NULL,
   ANG REAL(16,10) NOT NULL,
   -- 另有100+对应货币字段
   PRIMARY KEY (ID)
);

请问如何在Java和Spring Boot中实现该JSON到MySQL表的映射与数据写入?是否必须创建包含100余个字段的POJO,有没有更优的实现方式?


实现方案

一、传统POJO映射方式(不推荐)

如果采用这种方式,确实需要创建包含所有100+货币字段的实体类,配合Spring Data JPA或MyBatis完成映射:

  1. 创建实体类
@Entity
@Table(name = "tblData")
public class CurrencyRate {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    
    @Column(name = "base_currency")
    private String baseCurrency;
    
    @Column(name = "data_date")
    private LocalDate dataDate;
    
    // 示例货币字段,需补充其余100+字段
    private BigDecimal AED;
    private BigDecimal AFN;
    private BigDecimal ANG;
    
    // 构造器、Getter、Setter方法
}
  1. 数据写入
    使用Spring Data JPA时,定义JpaRepository接口后直接调用save()方法;使用MyBatis则编写对应的XML映射文件或注解SQL完成插入。

这种方式的弊端非常明显:实体类极度臃肿,新增或删除货币字段时必须同步修改实体类和表结构,维护成本极高。

二、更优的动态处理方案(推荐)

无需创建全字段POJO,利用Jackson解析JSON结合JDBC/MyBatis的动态SQL即可实现,灵活性和维护性更强:

方案1:基于JDBC Template动态拼接SQL

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.sql.Date;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

@Service
public class CurrencyRateService {
    private final JdbcTemplate jdbcTemplate;
    private final ObjectMapper objectMapper;

    public CurrencyRateService(JdbcTemplate jdbcTemplate, ObjectMapper objectMapper) {
        this.jdbcTemplate = jdbcTemplate;
        this.objectMapper = objectMapper;
    }

    public void saveCurrencyRate(String jsonStr) throws Exception {
        JsonNode rootNode = objectMapper.readTree(jsonStr);
        // 提取基础字段
        String baseCurrency = rootNode.get("basecurrency").asText();
        LocalDate dataDate = LocalDate.parse(rootNode.get("data_date").asText());
        JsonNode dataNode = rootNode.get("data");

        // 动态拼接插入字段和占位符
        StringBuilder columns = new StringBuilder("base_currency, data_date");
        StringBuilder placeholders = new StringBuilder("?, ?");
        List<Object> params = new ArrayList<>();
        params.add(baseCurrency);
        params.add(Date.valueOf(dataDate));

        // 遍历所有货币汇率字段
        dataNode.fields().forEachRemaining(entry -> {
            String currencyCode = entry.getKey();
            BigDecimal rate = entry.getValue().decimalValue();
            columns.append(", ").append(currencyCode);
            placeholders.append(", ?");
            params.add(rate);
        });

        // 执行插入
        String sql = String.format("INSERT INTO tblData (%s) VALUES (%s)", columns, placeholders);
        jdbcTemplate.update(sql, params.toArray());
    }
}

方案2:基于MyBatis动态SQL

  1. 定义Mapper接口
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;

import java.time.LocalDate;
import java.util.Map;

public interface CurrencyRateMapper {
    @Insert("<script>" +
            "INSERT INTO tblData (base_currency, data_date" +
            "<foreach collection='rateMap.keys' item='currency' separator=','>" +
            ", #{currency}" +
            "</foreach>" +
            ") VALUES (#{baseCurrency}, #{dataDate}" +
            "<foreach collection='rateMap.values' item='rate' separator=','>" +
            ", #{rate}" +
            "</foreach>" +
            ")</script>")
    void insertCurrencyRate(@Param("baseCurrency") String baseCurrency,
                            @Param("dataDate") LocalDate dataDate,
                            @Param("rateMap") Map<String, BigDecimal> rateMap);
}
  1. 业务层解析并调用
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;

@Service
public class CurrencyRateService {
    private final CurrencyRateMapper currencyRateMapper;
    private final ObjectMapper objectMapper;

    public CurrencyRateService(CurrencyRateMapper currencyRateMapper, ObjectMapper objectMapper) {
        this.currencyRateMapper = currencyRateMapper;
        this.objectMapper = objectMapper;
    }

    public void saveCurrencyRate(String jsonStr) throws Exception {
        JsonNode rootNode = objectMapper.readTree(jsonStr);
        String baseCurrency = rootNode.get("basecurrency").asText();
        LocalDate dataDate = LocalDate.parse(rootNode.get("data_date").asText());
        JsonNode dataNode = rootNode.get("data");

        // 将汇率字段转为Map
        Map<String, BigDecimal> rateMap = new HashMap<>();
        dataNode.fields().forEachRemaining(entry -> 
            rateMap.put(entry.getKey(), entry.getValue().decimalValue())
        );

        // 调用Mapper插入数据
        currencyRateMapper.insertCurrencyRate(baseCurrency, dataDate, rateMap);
    }
}

方案总结

  • 动态方案无需维护臃肿的POJO,新增或调整货币字段时,只要表结构同步更新,代码无需修改,扩展性和维护性远优于传统POJO方式。
  • 若后续需要查询单个货币字段,同样可以通过动态SQL实现,无需修改实体类或Mapper接口。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 21:57:35