开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情
在上面的文章中,我们可以看到 我们采用了几种实现方式查询,结果都可以正确的实现 下面我们把业务实现逻辑及核心代码展示, 这样我们在使用mybatis的时候才能得心应手,不管是Example 还是Criteria 还是Weekend 或者是 注解结合XML的实现方式, 我们都能应付自如
本文 我们着重介绍下 mybatis如何映射Map结构结果实现
查询逻辑的业务
1.1 application.properties配置
server.port=8800
spring.datasource.druid.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.druid.username=root
spring.datasource.druid.password=root
spring.datasource.druid.max-active=20
spring.datasource.druid.initial-size=5
spring.datasource.druid.min-idle=5
spring.datasource.druid.min-evictable-idle-time-millis=300000
spring.datasource.druid.max-wait=60000
spring.datasource.druid.validation-query=select 1
spring.datasource.druid.test-on-borrow=false
spring.datasource.druid.test-on-return=false
spring.datasource.druid.test-while-idle=true
spring.datasource.druid.time-between-eviction-runs-millis=60000
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
mybatis.mapper-locations=classpath:sqlmapper/*Mapper.xml
2.映射结果集Map结构实现
文档对resultType属性的表述:resultType结果的类型。通常 MyBatis 可以推断出来,但是为了更加准确,写上也不会有什么问题。MyBatis 允许将任何简单类型用作主键的类型,包括字符串。如果生成列不止一个,则可以使用包含期望属性的 Object 或 Map。
2.1 单个对象Map结构返回
如果需要把所有的字段 全部都转化成Map结构
- Map的key 就是 column字段名字比如 "user_id", "address", "is_del", 区分大小写及下划线
- value 就是返回的对象object 就是自己定义的UserInfoPO的字段的value信息
Mapper文件
Map<String, Object> map1User(@Param(value = "userid") String userid);
XML文件, 在XML中定义 SQL语句 如下:
<!-- 单个字段转化为Map结构 -->
<select id="map1User" resultType="map">
select * from user_info where user_id = #{userid}
</select>
查询结果如下:
2.2 多条数据如果用上面的查询会出现什么问题?
如果查到的是多个对象 现在数据有 两条数据 user_id= 456的 记录, 我们看下如果 用上面的map结构会出现什么问题
报错信息如下:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed;
nested exception is org.apache.ibatis.exceptions.TooManyResultsException:
Expected one result (or null) to be returned by selectOne(), but found: 2] with root cause
org.apache.ibatis.exceptions.TooManyResultsException:
Expected one result (or null) to be returned by selectOne(), but found: 2
2.3 多个UserInfo 指定Key 结果返回
多个UserInfo Map集合返回,指定Key字段 上面的情况我们只是记录了一条数据并返回了Map, 如果我们想查询多个用户数据, 全都指定了字段作为 返回结果的Key应该如何处理 ?
通过使用@MapKey注解来解决上面的问题
先看下官方文档中对于@Mapkey的表述:
这是一个用在返回值为 Map 的方法上的注解。它能够将存放对象的 List 转化为 key 值为对象的某一属性的 Map。属性有: value,填入的是对象的属性名,作为 Map 的 key 值。
我们可以使用@Mapkey注解指定封装map时使用对象的哪个属性来作为key,通常我们使用主键就可以,或者唯一索引,确保key不会重复。
@MapKey("user_id")
Map<String, UserInfoPO> nameUserMap();
XML文件实现
<!-- 指定Key的多个Map-->
<select id="nameUserMap" resultType="java.util.Map">
select * from user_info
</select>
查询结果如下: 可以看到 查询结果 14条记录, 结果Map中只有13条, 有一个user_id是重复的 456 Map中取的是 后面的 nn替换掉了前面的mm 记录
2.3 查询个别字段映射到新的PO
如果我现在只需要 2个字段 比如我只需要 id和name, 应该如何处理? 我们需要新建一个 对象, 制定resultType类型即可
比如我们需要 city及count信息, 只需要 新建PO实体类UserCity信息, 对应的就是 city字段及count字段信息
public class UserCity {
private String city;
private String count;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCount() {
return count;
}
public void setCount(String count) {
this.count = count;
}
}
然后 定义XML文件及Mapper文件
Mapper文件
List<UserCity> countUser(@Param("age") Integer age, @Param("names") List<String> names);
XML文件
<select id="countUser" resultType="com.jzj.tdmybatis.domain.po.UserCity">
select address as city , count(*) as count from user_info
where user_name in
<foreach close=")" collection="names" item="iterm" open="(" separator=",">
#{iterm}
</foreach>
group by city
</select>
然后即可实现字段映射到UserCity上
3 业务Service及Controller逻辑
3.1 TestController 测试API
采用 6 种方式 实现了 mybatis的查询逻辑
package com.jzj.tdmybatis.controller;
import cn.hutool.json.JSONUtil;
import com.jzj.tdmybatis.domain.po.UserCity;
import com.jzj.tdmybatis.domain.po.UserInfoPO;
import com.jzj.tdmybatis.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName TestController
* @Description
* @Author jiazijie
* @Date 2023/2/2 22:05
*/
@RestController
@Slf4j
public class TestController {
@Resource
private IUserService userService;
/**
* 探活接口
*/
@RequestMapping("/temp/ping")
@ResponseBody
public Object ping() {
return "pong";
}
/**
* 查询user接口
*/
@RequestMapping("/temp/user")
@ResponseBody
public Object user(String id) {
//测试重复的
UserInfoPO user = userService.getUser(id);
log.info("user====", JSONUtil.toJsonStr(user));
return user;
}
/**
* 查询user接口
*/
@RequestMapping("/temp/query1")
@ResponseBody
public Object query1() {
//测试注解信息
// 找 年龄 > 30岁的员工
List<UserInfoPO> userInfoPOS = userService.selectByAge(30);
log.info("query1====", JSONUtil.toJsonStr(userInfoPOS));
return userInfoPOS;
}
/**
* 查询user接口
*/
@RequestMapping("/temp/query2")
@ResponseBody
public Object query2() {
//测试XML信息
// 找 年龄 > 30岁的员工 且 名字是 aa或者bb, cc的员工
List<String> names = new ArrayList<>();
names.add("aa");
names.add("bb");
names.add("cc");
List<UserCity> userInfoPOS = userService.countUser(30, names);
log.info("query2====", JSONUtil.toJsonStr(userInfoPOS));
return userInfoPOS;
}
/**
* 查询user接口
*/
@RequestMapping("/temp/query3")
@ResponseBody
public Object query3() {
//测试XML信息
// 找 年龄 > 30岁的员工 且 名字是 aa或者bb, cc的员工
List<String> names = new ArrayList<>();
names.add("aa");
names.add("bb");
names.add("cc");
List<UserInfoPO> userInfoPOS = userService.getUserExample(1, names);
log.info("query3====", JSONUtil.toJsonStr(userInfoPOS));
return userInfoPOS;
}
/**
* 查询user接口
*/
@RequestMapping("/temp/query4")
@ResponseBody
public Object query4() {
//测试Example信息
// 找 年龄 > 30岁的员工 且 名字是 aa或者bb, cc的员工
List<String> names = new ArrayList<>();
names.add("aa");
names.add("bb");
names.add("cc");
List<UserInfoPO> userExample = userService.getUserExample(1, names);
log.info("query4====", JSONUtil.toJsonStr(userExample));
return userExample;
}
/**
* 查询user接口
*/
@RequestMapping("/temp/query5")
@ResponseBody
public Object query5() {
//测试Builder 信息
// 找 年龄 > 30岁的员工 且 名字是 aa或者bb, cc的员工
List<String> names = new ArrayList<>();
names.add("aa");
names.add("bb");
names.add("cc");
List<UserInfoPO> userBuilder = userService.getUserBuilder(1, names);
log.info("query5====", JSONUtil.toJsonStr(userBuilder));
return userBuilder;
}
/**
* 查询user接口
*/
@RequestMapping("/temp/query6")
@ResponseBody
public Object query6() {
//测试Weekend 信息
// 找 年龄 > 30岁的员工 且 名字是 aa或者bb, cc的员工
List<String> names = new ArrayList<>();
names.add("aa");
names.add("bb");
names.add("cc");
List<UserInfoPO> userWeekend = userService.getUserWeekend(30, names);
log.info("query6====", JSONUtil.toJsonStr(userWeekend));
return userWeekend;
}
/**
* 探活接口
*/
@RequestMapping("/temp/map1")
@ResponseBody
public Object map1(String uid) {
Map<String, Object> usermap = userService.map1User(uid);
//使用Mybatis返回Map结构时字段别名需要用双引号包裹否则别名会全部大写或小写
log.info("key:user_id value:"+usermap.get("user_id"));
log.info("usermap=="+usermap);
return "pong";
}
/**
* 探活接口
*/
@RequestMapping("/temp/map2")
@ResponseBody
public Object map2(String uid) {
Map<String, UserInfoPO> usermap = userService.nameUserMap();
log.info("usermap=="+JSONUtil.toJsonStr(usermap));
return "pong";
}
}
1.3 UserMapper mapper文件的实现
package com.jzj.tdmybatis.repository.mapper;
import com.jzj.tdmybatis.config.BaseMapper;
import com.jzj.tdmybatis.domain.po.UserCity;
import com.jzj.tdmybatis.domain.po.UserInfoPO;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Map;
public interface UserInfoMapper extends BaseMapper<UserInfoPO> {
@Select("select * from user_info where age > #{age}")
List<UserInfoPO> selectGreaterAge(@Param("age") Integer age);
List<UserCity> countUser(@Param("age") Integer age, @Param("names") List<String> names);
Map<String, Object> map1User(@Param(value = "userid") String userid);
@MapKey("user_id")
Map<String, UserInfoPO> nameUserMap();
}
1.4 XML UserMapper.xml的实现
<?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.jzj.tdmybatis.repository.mapper.UserInfoMapper">
<resultMap id="BaseResultMap" type="com.jzj.tdmybatis.domain.po.UserInfoPO">
<!--
WARNING - @mbg.generated
-->
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="user_id" jdbcType="CHAR" property="userId"/>
<result column="user_name" jdbcType="CHAR" property="userName"/>
<result column="age" jdbcType="INTEGER" property="age"/>
<result column="address" jdbcType="VARCHAR" property="address"/>
<result column="order_ids" jdbcType="CHAR" property="orderIds"/>
<result column="goods" jdbcType="CHAR" property="goods"/>
<result column="sort_order" jdbcType="INTEGER" property="sortOrder"/>
<result column="is_del" jdbcType="TINYINT" property="isDel"/>
<result column="is_del2" jdbcType="TINYINT" property="isDel2"/>
<result column="addtime" jdbcType="BIGINT" property="addtime"/>
<result column="modtime" jdbcType="BIGINT" property="modtime"/>
</resultMap>
<select id="countUser" resultType="com.jzj.tdmybatis.domain.po.UserCity">
select address as city , count(*) as count from user_info
where user_name in
<foreach close=")" collection="names" item="iterm" open="(" separator=",">
#{iterm}
</foreach>
group by city
</select>
<select id="map1User" resultType="map">
select * from user_info where user_id = #{userid}
</select>
<!-- 指定Key的多个Map-->
<select id="nameUserMap" resultType="java.util.Map">
select * from user_info
</select>
</mapper>