Mybatis 返回 Map 对象
一、场景介绍
假设有如下一张学生表:
CREATE TABLE `student` (`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',`name` varchar(100) NOT NULL COMMENT '姓名',`gender` varchar(10) NOT NULL COMMENT '性别',`grade` int NOT NULL COMMENT '年级',PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='学生信息表';
我们通过一组 ids,想获得 id 跟学生对象的映射 Map<Integer, Student>,可以这样做:
1、先通过 ids 获取对象列表
2、再通过 stream 流式运算得到 id-Student 映射
这样做虽然也没有问题,但是这样 service 层就会散落一堆这样流式运算的代码。不是很美观,应该在DAO层就提供这种能力。Mybatis 提供给我们查询 Map 的方式。
@Service
public class StudentServiceImpl implements StudentService {@Autowiredprivate StudentMapper mapper;@Overridepublic Map<Integer, Student> findMapByIds(List<Integer> ids) {List<Student> students = mapper.listByIds(ids);Map<Integer, Student> map = students.stream().collect(Collectors.toMap(Student::getId, Function.identity()));return map;}
}
---------------------------------------------------------------
@Test
public void test() {List<Integer> list = Arrays.asList(1,2,3);Map<Integer, Student> map = studentService.findMapByIds(list);System.out.println(map);
}输出:
{1=Student(id=1, name=小明, gender=male, grade=1), 2=Student(id=2, name=小红, gender=female, grade=2), 3=Student(id=3, name=小李, gender=male, grade=3)}
二、Mybatis @MapKey 方式
Mybatis 提供了 @MapKey 注解,注解的 value 用来指定 key 的取值字段。
可以看到,效果是一样的。
@Mapper
public interface StudentMapper {/*** 这种基础的查询,不应该先获取 List 流,然后再转换,* 这样会使整个项目散落一地这种代码* 应该在DAO层就提供这种能力*/@MapKey("id")Map<Integer, Student> findMapByIds(List<Integer> ids);
}
-------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.study.student.mapper.StudentMapper"><select id="findMapByIds" resultType="com.study.student.entity.Student">select *from student s<where>and s.id in<foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach></where></select></mapper>
-------------------------------------------------------------
@Service
public class StudentServiceImpl implements StudentService {@Autowiredprivate StudentMapper mapper;@Overridepublic Map<Integer, Student> findMapByIds(List<Integer> ids) {/*List<Student> students = mapper.listByIds(ids);Map<Integer, Student> map = students.stream().collect(Collectors.toMap(Student::getId, Function.identity()));return map;*/return mapper.findMapByIds(ids);}
}
-------------------------------------------------------------
@Test
public void test() {List<Integer> list = Arrays.asList(1,2,3);Map<Integer, Student> map = studentService.findMapByIds(list);System.out.println(map);
}
输出:
{1=Student(id=1, name=小明, gender=male, grade=1), 2=Student(id=2, name=小红, gender=female, grade=2), 3=Student(id=3, name=小李, gender=male, grade=3)}
但如果 @MapKey 的 value 配置了记录重复的字段会怎么样?
就比如,@MapKey("grade"),grade = 1,2,3 的记录并非唯一。
@Mapper
public interface StudentMapper {List<Student> listByIds(List<Integer> ids);/*** @MapKey 的 value 是 grade 这种非唯一字段*/@MapKey("grade")Map<Integer, Student> findMapByIds(List<Integer> ids);
}
这个时候会发现,返回的记录被覆盖了。
id in [1,6] 的 grade=1 的记录有 小明跟小智,
小明先查询出来,
map.put(1, Student(id=1, name=小明, gender=male, grade=1))
小智后查询出来,
map.put(1, Student(id=6, name=小智, gender=male, grade=1))
同一个key,小智覆盖了小明。
那如果我们希望返回 Map<grade:Integer, List<Student>> 怎么办呢?
@Test
public void test2() {List<Integer> list = Arrays.asList(1,2,3,4,5,6);Map<Integer, Student> map = studentService.findMapByIds(list);System.out.println(map);
}
输出:
{1=Student(id=6, name=小智, gender=male, grade=1), 2=Student(id=4, name=小林, gender=male, grade=2), 3=Student(id=5, name=小婷, gender=female, grade=3)}
三、Stream 返回 Map<Integer, List<Student>>
遗憾的是,笔者找了 Mybatis 跟 MybatisPlus 也没找到此类方法,所以这一块,还是只能用流式计算来做。
@Mapper
public interface StudentMapper {List<Student> listByIds(List<Integer> ids);
}
-------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.study.student.mapper.StudentMapper"><select id="listByIds" resultType="cn.al.admin.entity.finance.Student">select *from student s<where>and s.id in<foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach></where></select></mapper>
-------------------------------------------------------------
@Service
public class StudentServiceImpl implements StudentService {@Autowiredprivate StudentMapper mapper;@Overridepublic Map<Integer, List<Student>> getMapByIds(List<Integer> ids) {List<Student> students = mapper.listByIds(ids);return students.stream().collect(Collectors.groupingBy(Student::getGrade));}
}
-------------------------------------------------------------
@Test
public void test3() {List<Integer> list = Arrays.asList(1,2,3,4,5,6);Map<Integer, List<Student>> map = studentService.getMapByIds(list);System.out.println(map);}
输出:
{1=[Student(id=1, name=小明, gender=male, grade=1), Student(id=6, name=小智, gender=male, grade=1)], 2=[Student(id=2, name=小红, gender=female, grade=2), Student(id=4, name=小林, gender=male, grade=2)], 3=[Student(id=3, name=小李, gender=male, grade=3), Student(id=5, name=小婷, gender=female, grade=3)]}
四、MybatisPlus 返回 List<Map<String, Object>>
如果希望查询返回 List<Map<String, Object>> Map 的 key 是数据库 column name
package com.study.student.mapper;import com.study.student.entity.Student;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.*;@Mapper
public interface StudentMapper extends BaseMapper<Student> {
}
------------------------------------------------------------
package com.study.student.service.impl;import com.study.student.entity.Student;
import com.study.student.mapper.StudentMapper;
import com.study.student.service.StudentService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Map;@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {@Overridepublic List<Map<String, Object>> getMapList(List<Integer> ids) {LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<>();wrapper.in(Student::getId, ids);return this.getBaseMapper().selectMaps(wrapper);}
}
------------------------------------------------------------
@Test
public void test4() {List<Integer> list = Arrays.asList(1,2,3,4,5,6);List<Map<String, Object>> map = studentService.getMapList(list);System.out.println(map);
}
输出:
[{gender=male, grade=1, name=小明, id=1, photo_url=url1}, {gender=female, grade=2, name=小红, id=2, photo_url=url2}, {gender=male, grade=3, name=小李, id=3, photo_url=url3}, {gender=male, grade=2, name=小林, id=4, photo_url=url4}, {gender=female, grade=3, name=小婷, id=5, photo_url=url5}, {gender=male, grade=1, name=小智, id=6, photo_url=url6}]
五、JSON 返回 List<Map<String, Object>>
如果希望查询返回 List<Map<String, Object>> Map 的 key 是对象 property。需要借助 JSON 工具类,比如 cn.hutool.core.bean.BeanUtil#beanToMap
package com.study.student.service.impl;import com.study.student.entity.Student;
import com.study.student.mapper.StudentMapper;
import com.study.student.service.StudentService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;import cn.hutool.core.bean.BeanUtil;import java.util.List;
import java.util.Map;@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {@Overridepublic List<Map<String, Object>> getMapList(List<Integer> ids) {List<Student> students = this.listByIds(ids);return students.stream().map(BeanUtil::beanToMap).collect(Collectors.toList());}
}
------------------------------------------------------------
@Test
public void test5() {List<Integer> list = Arrays.asList(1,2,3,4,5,6);List<Map<String, Object>> map = studentService.getMapList(list);System.out.println(map);
}
输出:
[{id=1, name=小明, gender=male, grade=1, photoUrl=url1}, {id=2, name=小红, gender=female, grade=2, photoUrl=url2}, {id=3, name=小李, gender=male, grade=3, photoUrl=url3}, {id=4, name=小林, gender=male, grade=2, photoUrl=url4}, {id=5, name=小婷, gender=female, grade=3, photoUrl=url5}, {id=6, name=小智, gender=male, grade=1, photoUrl=url6}]
六、MybatisPlus 返回 Map<String, Object>
Map 的 key 是数据库 column name
package com.study.student.service.impl;import com.study.student.entity.Student;
import com.study.student.mapper.StudentMapper;
import com.study.student.service.StudentService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Map;@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {@Overridepublic Map<String, Object> getMapById(Integer id) {LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<>();wrapper.eq(Student::getId, id);return this.getMap(wrapper);}
}
------------------------------------------------------------
@Test
public void test6() {Map<String, Object> map = studentService.getMapById(6);System.out.println(map);}
输出:
{gender=male, grade=1, name=小智, id=6, photo_url=url6}
七、JSON 返回 Map<String, Object>
Map 的 key 是对象 property
package com.study.student.service.impl;import com.study.student.entity.Student;
import com.study.student.mapper.StudentMapper;
import com.study.student.service.StudentService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;import cn.hutool.core.bean.BeanUtil;import java.util.List;
import java.util.Map;@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {@Overridepublic Map<String, Object> getMapById(Integer id) {Student student = this.getById(id);return BeanUtil.beanToMap(student);}
}
------------------------------------------------------------
@Test
public void test7() {Map<String, Object> map = studentService.getMapById(6);System.out.println(map);
}
输出:
{id=6, name=小智, gender=male, grade=1, photoUrl=url6}
相关文章:

Mybatis 返回 Map 对象
一、场景介绍 假设有如下一张学生表: CREATE TABLE student (id int NOT NULL AUTO_INCREMENT COMMENT 主键,name varchar(100) NOT NULL COMMENT 姓名,gender varchar(10) NOT NULL COMMENT 性别,grade int NOT NULL COMMENT 年级,PRIMARY KEY (id) ) ENGINEInnoD…...

Vue3(三)路由基本使用、工作模式(history,hash)、query传参和param传参、props配置、编程式路由导航
文章目录 一、路由的基本使用二、路由器的工作模式三、RouterLink中to的两种写法四、嵌套路由五、路由传参1. query传参2. params传参 六、路由的propos配置七、编程式路由导航 一、路由的基本使用 安装:npm i vue-router 在src/pages文件下,创建三个路…...

TypeScript概念讲解
简单来说,TypeScript 是 JavaScript 的一个超集,支持 ECMAScript 6 标准; TypeScript 由微软开发的自由和开源的编程语言; TypeScript 设计目标是开发大型应用,它可以编译成纯 JavaScript,编译出来的 Jav…...

C++ | Leetcode C++题解之第437题路径总和III
题目: 题解: class Solution { public:unordered_map<long long, int> prefix;int dfs(TreeNode *root, long long curr, int targetSum) {if (!root) {return 0;}int ret 0;curr root->val;if (prefix.count(curr - targetSum)) {ret pref…...
回复《对话损友 2》
回复《对话损友 2》 承蒙贵人挂念,亦感激贵人给予这般交流的契机(对话损友 2 -- 回复-CSDN博客)。我自身也一直期望能留存些岁月的痕迹,然而却常困惑于不知哪些事物值得铭记,哪些又应被永远忘却。 随着时光流转&#x…...

MySQL - 运维篇
一、日志 1. 错误日志 2. 二进制日志 3. 查询日志 记录了所有的增删改查语句以及DDL语句 4. 慢查询日志 二、主从复制 1. 概述 2. 原理 3. 搭建 三、分库分表 1. 介绍 2. Mycat概述 3. Mycat入门 4. Mycat配置 5. Mycat分片 6. Mycat管理及监控 四、读写分离 1. 介绍 2. 一…...
WebGIS开发及市面上各种二三维GIS开发框架对比分析
GIS前端开发是现代WebGIS应用开发中非常重要的一环,通过前端开发框架,可以实现地图展示、交互、分析等功能。本文将介绍当前市面上常用的GIS前端开发框架,并进行对比分析。 Leaflet Leaflet是一款轻量级的开源地图库,它提供了丰…...

[论文精读]TorWard: Discovery, Blocking, and Traceback of Malicious Traffic Over Tor
期刊名称:IEEE Transactions on Information Forensics and Security 发布链接:TorWard: Discovery, Blocking, and Traceback of Malicious Traffic Over Tor | IEEE Journals & Magazine | IEEE Xplore 中文译名:TorWard:…...
pytest - 多线程提速
import timedef test1_test1():time.sleep(1)assert 1 1, "11"def test1_test2():time.sleep(1)assert 1 1, "11" 上面2个函数,执行情况: 正常执行时,花费 2.08s2个进程执行时,花费 1.18s2个线程执行时&a…...
python中logging的用法
logging.error 是 Python logging 模块中的一个方法,专门用于记录错误级别(ERROR)的日志信息。logging 模块是 Python 提供的标准日志工具,用于生成各种级别的日志消息,并支持日志的格式化和存储。 logging.error 的基…...

【YOLO目标检测车牌数据集】共10000张、已标注txt格式、有训练好的yolov5的模型
目录 说明图片示例 说明 数据集格式:YOLO格式 图片数量:10000(2000张绿牌、8000张蓝牌) 标注数量(txt文件个数):10000 标注类别数:1 标注类别名称:licence 数据集下载:车牌数据…...

gdb xterm 调试 openmpi 程序
1,编写编译一个openmpi程序 迭代计算 PI 的源程序: pi_reduce.c #include <stdio.h>#include <math.h> #include <mpi.h>double f(double); double f(double x) {return (4.0/(1.0x*x)); }int main(int argc, char* argv[]) {int d…...

【STM32】江科大STM32笔记汇总(已完结)
STM32江科大笔记汇总 STM32学习笔记课程简介(01)STM32简介(02)软件安装(03)新建工程(04)GPIO输出(05)LED闪烁& LED流水灯& 蜂鸣器(06)GPIO输入(07)按键控制LED 光敏传感器控制蜂鸣器(08)OLED调试工具(09)OLED显示屏(10)EXTI外部中断(11)对射式红外传感器计次 旋转编码器…...

Java基础扫盲(二)
想看Java基础扫盲(一)的可以观看我的上篇文章Java基础扫盲 目录 String为什么设计为不可变的 String有长度限制吗 为什么JDK9将String的char[]改为byte[] 泛型中K,T,V,E,Object,?等都代表什么含义 怎么修改一个类中使用了private修饰的String类型…...
兼容React的刮刮乐完整代码实现
需要兼容React的刮刮乐完整代码实现 在现代Web开发中,React作为一种流行的前端框架,为开发者提供了构建动态界面的强大工具。刮刮乐效果作为一种趣味性的用户交互,能够显著提升用户体验和参与度。本文将详细介绍如何在React项目中实现一个兼…...

PHP程序如何实现限制一台电脑登录?
PHP程序如何实现限制一台电脑登录? 可以使用以下几种方法: 1. IP地址限制:在PHP中,可以通过获取客户端的IP地址,然后与允许登录的IP地址列表进行比对。如果客户端的IP地址不在列表中,就禁止登录。 “php $…...
nodejs fs 模块的简介与相关案例
fs 文件系统模块 什么是 fs 文件系统模块? fs 模块是 Node.js 官方提供的、用来操作文件的模块。它提供了一系列的方法和属性,用来满足用户对文件的操作要求。* 例如: fs.readFile() 方法用来读取文件内容。fs.writeFile() 方法用来写入文…...

计算机毕业设计 基于Flask+Vue的博客系统 Python毕业设计 前后端分离 附源码 讲解 文档
🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…...

基于SSH的酒店管理系统的设计与实现 (含源码+sql+视频导入教程)
👉文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSH的酒店管理系统拥有两种角色 管理员:房间管理、房型管理、客户管理、预定管理、入住管理(到店入住、预定入住、正在入住)、账单管理、会员管理…...
消息队列10:为RabbitMq添加连接池
环境: win11rabbitmq-3.8.17.net 6.0RabbitMQ.Client 6.8.1vs2022 安装RabbitMq环境参照: window下安装rabbitmqlinux下安装rabbitmq 问题:rabbitmq的c#客户端没有自带连接池,所以需要手动实现。 简易实现如下: usi…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...

如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...

热烈祝贺埃文科技正式加入可信数据空间发展联盟
2025年4月29日,在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上,可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞,强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...

高考志愿填报管理系统---开发介绍
高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发,采用现代化的Web技术,为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## 📋 系统概述 ### 🎯 系统定…...
LangChain【6】之输出解析器:结构化LLM响应的关键工具
文章目录 一 LangChain输出解析器概述1.1 什么是输出解析器?1.2 主要功能与工作原理1.3 常用解析器类型 二 主要输出解析器类型2.1 Pydantic/Json输出解析器2.2 结构化输出解析器2.3 列表解析器2.4 日期解析器2.5 Json输出解析器2.6 xml输出解析器 三 高级使用技巧3…...

Centos 7 服务器部署多网站
一、准备工作 安装 Apache bash sudo yum install httpd -y sudo systemctl start httpd sudo systemctl enable httpd创建网站目录 假设部署 2 个网站,目录结构如下: bash sudo mkdir -p /var/www/site1/html sudo mkdir -p /var/www/site2/html添加测试…...