一、业务场景
在投注记录查询功能中,我们需要展示每个彩票期号(userId + lotteryIssue分组)的汇总数据(总金额、总注数),同时也要显示该期号下的所有明细投注记录。
解决方案:JSON_ARRAYAGG
MySQL 5.7+ 提供的 JSON_ARRAYAGG
函数完美解决了这个问题,它可以将多行数据聚合成一个JSON数组。
二、代码实现
1. 后端接口(Controller层)
@GetMapping("/records")
public AjaxResult records(HttpServletRequest request,@RequestParam(defaultValue = "1") Integer pageNum,@RequestParam(defaultValue = "20") Integer pageSize) {return service.records(request, pageNum, pageSize);
}
-
接收分页参数,调用服务层
2. 服务层(Service层)
public AjaxResult records(HttpServletRequest request, Integer pageNum, Integer pageSize) {UserVo user = JwtUtils.getUser(request.getHeader("token")); // 鉴权List<FastThreeBettingVo> list = mapper.selectRecordsByUserId(user.getUserId());return AjaxResult.success(list); // 返回带分级的数据
}
3. 数据结构(VO对象)
@Data
public class FastThreeBettingVo {// 用户private Long userId;// 期号private String lotteryIssue;// 总金额private BigDecimal totalAmount;// 总注数private Long totalCount;// 投注详情列表private List<FastThreeBettingDetail> children;// 手动设置 children 的方法public void setChildren(String detailsJson) {ObjectMapper objectMapper = new ObjectMapper();try {// 将 JSON 字符串解析为 List<xx>this.children = objectMapper.readValue(detailsJson, new TypeReference<List<FastThreeBettingDetail>>() {});// 对 children 按 lotteryIssue 倒序排序sortChildrenByLotteryIssueDesc();} catch (Exception e) {throw new RuntimeException("Failed to parse details JSON", e);}}// 按 lotteryIssue 倒序排序 children 的方法private void sortChildrenByLotteryIssueDesc() {if (this.children != null && !this.children.isEmpty()) {// 使用 Comparator 对 lotteryIssue 进行倒序排序this.children.sort((detail1, detail2) -> {String issue1 = detail1.getLotteryIssue();String issue2 = detail2.getLotteryIssue();return issue2.compareTo(issue1); // 倒序排序});}}
}
4. 数据结构(children对象)
@Data
public class FastThreeBettingDetail {// 期号private String lotteryIssue;// 玩法名称private String clzName;// 下注信息private String specialName;// 下注金额private BigDecimal amount;// 中奖状态 0=待开奖 1=中奖 2=未中奖private String winningStatus;// 中奖金额private BigDecimal winningAmount;
}
5. 核心SQL(Mapper层)
-
明细聚合:
JSON_ARRAYAGG
+JSON_OBJECT
将明细记录转为JSON数组
<select id="selectRecordsByUserId" parameterType="Long" resultType="com.ruoyi.ruoyiliushu.mo.ls_fast_three_user_betting.vo.FastThreeBettingVo">SELECTuser_id AS userId,lottery_issue AS lotteryIssue,SUM(amount) AS totalAmount,COUNT(*) AS totalCount,JSON_ARRAYAGG(JSON_OBJECT('lotteryIssue', lottery_issue,'clzName', clz_name,'specialName', special_name,'amount', amount,'winningStatus',CASE winning_statusWHEN 0 THEN '待开'WHEN 1 THEN '中奖'WHEN 2 THEN '未中'ELSE '未知'END,'winningAmount', winning_amount)) AS childrenFROMls_fast_three_user_bettingwhereuser_id = #{userId}group byuser_id,lottery_issueorder bylottery_issue desclimit 1</select>
6. 输出结构
{"msg": "操作成功","code": 200,"data": [{"userId": 11,"lotteryIssue": "2025020010","totalAmount": 6.00,"totalCount": 6,"children": [{"lotteryIssue": "2025020010","clzName": "豹子","specialName": "6,6,6","amount": 1.00,"winningStatus": "未中","winningAmount": 169.00},{"lotteryIssue": "2025020010","clzName": "豹子","specialName": "5,5,5","amount": 1.00,"winningStatus": "未中","winningAmount": 169.00},{"lotteryIssue": "2025020010","clzName": "豹子","specialName": "4,4,4","amount": 1.00,"winningStatus": "未中","winningAmount": 169.00},{"lotteryIssue": "2025020010","clzName": "豹子","specialName": "3,3,3","amount": 1.00,"winningStatus": "未中","winningAmount": 169.00},{"lotteryIssue": "2025020010","clzName": "豹子","specialName": "2,2,2","amount": 1.00,"winningStatus": "未中","winningAmount": 169.00},{"lotteryIssue": "2025020010","clzName": "豹子","specialName": "1,1,1","amount": 1.00,"winningStatus": "未中","winningAmount": 169.00}]}]
}
三、函数详解
1. JSON_OBJECT 函数
功能
JSON_OBJECT
用于创建一个JSON对象(键值对集合)
语法
sqlJSON_OBJECT(key1, value1, key2, value2, ...)
代码示例
sqlJSON_OBJECT('lotteryIssue', lottery_issue,'clzName', clz_name,'specialName', special_name,'amount', amount,'winningStatus', CASE winning_status... END,'winningAmount', winning_amount
)
运行效果
将每行数据转换为:
json{"lotteryIssue": "2025020010","clzName": "豹子","specialName": "6,6,6","amount": 1.00,"winningStatus": "未中","winningAmount": 169.00
}
2. JSON_ARRAYAGG 函数
功能
JSON_ARRAYAGG
将多行数据聚合成一个JSON数组
语法
sqlJSON_ARRAYAGG(expression)
代码示例
sqlJSON_ARRAYAGG(JSON_OBJECT(...) -- 将每行的JSON对象聚合成数组
) AS children
运行效果
将分组内的所有明细记录转换为:
json[{第一条明细记录},{第二条明细记录},...
]
四. 注意事项
-
MySQL版本要求:5.7+ 支持JSON函数
-
性能考虑:大数据量时可能影响性能
-
字段别名:Java VO中的字段名需与SQL中的别名一致
-
NULL处理:默认会包含NULL值,可用
NULL ON NULL
控制
这两个函数配合使用,完美解决了SQL查询中"一对多"关系的结构化输出需求。