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

Java中如何返回多级结构ResultSet并转换为无冗余JSON?

解决多表关联ResultSet转多级JSON的冗余问题

核心思路

不用拆分查询,而是在遍历ResultSet时手动做内存分组聚合,把重复的主表数据合并,子表数据整理成列表,最后用JSON库序列化出目标结构。

关键前提

先修改你的SQL,必须加上im.InvoiceId作为分组唯一标识(否则无法区分不同发票):

String sql = 
  "select im.InvoiceId, im.InvoiceDate, s.StoreId, s.StoreName, id.ItemId, id.Quantity " +
  "from InvoiceMaster as im " +
  "left join InvoiceDetail as id on id.InvoiceId = im.InvoiceId " +
  "left join Stores as s on s.StoreId = im.StoreId ";

步骤1:定义对应实体类

创建和目标JSON结构匹配的Java类(可以用Lombok简化getter/setter,也可手动编写):

// 发票主信息类
public class Invoice {
    private String invoiceDate;
    private Store store;
    private List<InvoiceDetail> invoiceDetails = new ArrayList<>();
    
    // 手动添加getter、setter方法
}

// 门店类
public class Store {
    private Integer storeId;
    private String storeName;
    
    // 手动添加getter、setter方法
}

// 发票明细类
public class InvoiceDetail {
    private Integer itemId;
    private Integer quantity;
    
    // 手动添加getter、setter方法
}

// 最终返回的顶层结构类
public class InvoiceResponse {
    private long selectTime;
    private List<Invoice> invoices;
    
    // 手动添加getter、setter方法
}

步骤2:遍历ResultSet并分组聚合

用Map<String, Invoice>(key为InvoiceId)缓存已处理的发票,避免重复创建对象:

// 记录查询耗时
long startTime = System.currentTimeMillis();
rs = connection.executeQuery(sql);
long selectTime = System.currentTimeMillis() - startTime;

Map<String, Invoice> invoiceMap = new HashMap<>();

while (rs.next()) {
    String invoiceId = rs.getString("InvoiceId");
    // 先检查缓存中是否已有该发票
    Invoice invoice = invoiceMap.get(invoiceId);
    
    if (invoice == null) {
        // 无缓存则创建新发票对象
        invoice = new Invoice();
        invoice.setInvoiceDate(rs.getString("InvoiceDate"));
        
        // 初始化门店信息
        Store store = new Store();
        store.setStoreId(rs.getInt("StoreId"));
        store.setStoreName(rs.getString("StoreName"));
        invoice.setStore(store);
        
        // 将新发票存入缓存
        invoiceMap.put(invoiceId, invoice);
    }
    
    // 处理发票明细(判断非空避免空指针)
    if (rs.getString("ItemId") != null) {
        InvoiceDetail detail = new InvoiceDetail();
        detail.setItemId(rs.getInt("ItemId"));
        detail.setQuantity(rs.getInt("Quantity"));
        invoice.getInvoiceDetails().add(detail);
    }
}

// 把缓存中的发票转成列表
List<Invoice> invoiceList = new ArrayList<>(invoiceMap.values());

// 封装成最终返回结构
InvoiceResponse response = new InvoiceResponse();
response.setSelectTime(selectTime);
response.setInvoices(invoiceList);

步骤3:序列化生成JSON

用Jackson(Java常用JSON库)把实体类转成目标JSON:

ObjectMapper objectMapper = new ObjectMapper();
String jsonResult = objectMapper.writeValueAsString(response);
// 直接返回或输出该jsonResult即可

方案优势

  • 仅执行一次SQL查询,避免拆分查询带来的N+1性能问题;
  • 内存分组的开销极小,可忽略不计;
  • 最终生成的JSON完全符合你需要的多级嵌套结构,无冗余数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 17:58:25