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

JPA如何从Feeder、Monthlyfeederdetails多表提取数据插入Report表

实现方案

方式一:使用原生SQL @Query 直接实现批量插入(性能最优,和你熟悉的原生SQL逻辑完全一致)

这种方式直接在数据库层面完成查询+插入操作,不需要把中间数据拉到Java内存,适合所有场景,尤其是数据量较大的情况。
首先创建ReportRepository接口,继承JpaRepository,直接写原生插入语句即可:

import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.transaction.annotation.Transactional;

public interface ReportRepository extends CrudRepository<Report, Integer> {

    @Modifying // 标识这是写操作
    @Transactional // 增删改必须加事务
    @Query(value = "INSERT INTO `report of caifi and caidi` (feeder_name, feeder_type, no_of_afcon, duration_of_intr, no_of_afconXduration_of_intr) " +
            "SELECT f.feeder_name, f.feeder_type, m.no_of_afcon, m.duration_of_intr, m.duration_of_intr * m.no_of_afcon " +
            "FROM feeder f INNER JOIN monthlyfeederdetails m ON f.feeder_id = m.feeder_id",
            nativeQuery = true)
    void batchGenerateReport();

    // 如果需要加过滤条件比如按月份、年份生成报表,直接加参数即可,示例:
    @Modifying
    @Transactional
    @Query(value = "INSERT INTO `report of caifi and caidi` (feeder_name, feeder_type, no_of_afcon, duration_of_intr, no_of_afconXduration_of_intr) " +
            "SELECT f.feeder_name, f.feeder_type, m.no_of_afcon, m.duration_of_intr, m.duration_of_intr * m.no_of_afcon " +
            "FROM feeder f INNER JOIN monthlyfeederdetails m ON f.feeder_id = m.feeder_id WHERE m.month = ?1 AND m.year = ?2",
            nativeQuery = true)
    void batchGenerateReportByMonth(int month, int year);
}

需要调用的时候直接注入ReportRepository,执行对应的方法即可。


方式二:先查询关联数据再组装存储(适合数据量小、需要额外业务逻辑处理的场景)

如果需要在插入前对数据做额外校验、修改,就用这种方式:

  1. 先关联查询Feeder和Monthlyfeederdetails的对应字段
  2. 遍历结果组装Report实体,计算乘积字段
  3. 批量保存所有Report实体

示例Service层代码:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;

@Service
public class ReportService {
    @Autowired
    private ReportRepository reportRepository;
    // 自定义查询获取两个表关联的所需字段,可用Object数组接收,也可自定义DTO投影接收
    @Autowired
    private FeederRepository feederRepository;

    @Transactional
    public void generateReport() {
        // FeederRepository中自定义关联查询方法,返回的数组顺序对应[feeder_name,feeder_type,no_of_afcon,duration_of_intr]
        List<Object[]> rawData = feederRepository.getReportRawData();
        List<Report> reportList = new ArrayList<>();

        for (Object[] row : rawData) {
            Report report = new Report();
            report.setFeeder_name((String) row[0]);
            report.setFeeder_type((Integer) row[1]);
            report.setNo_of_afcon((Integer) row[2]);
            report.setDuration_of_intr((Integer) row[3]);
            // 计算乘积字段
            report.setNo_of_afconXduration_of_intr(report.getNo_of_afcon() * report.getDuration_of_intr());
            reportList.add(report);
        }
        // 批量保存
        reportRepository.saveAll(reportList);
    }
}

注意事项

  • 优先选择方式一实现,性能比方式二高很多,也不需要额外写关联查询逻辑
  • 务必给Report实体类补全所有字段的getter、setter方法,否则会出现字段映射异常
  • 如果两个表的关联逻辑有特殊要求,直接修改SQL中JOIN的条件即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 01:54:06