【DB系列】Mybatis之ResultMap、ResultType返回结果使用姿势

语言: CN / TW / HK

在使用mybatis进行数据库操作时,如果希望将返回结果映射为项目中定义的实体对象Entity时,ResultMap与ResultType就很重要了;它们两的主要区别在于ResultType指定指定实体对象,ResultMap则定义数据库字段与实体的映射关系

接下来通过简单的实例来看一下这两种的使用姿势

I. 环境配置

我们使用SpringBoot + Mybatis + MySql来搭建实例demo

  • springboot: 2.2.0.RELEASE
  • mysql: 5.7.22

1. 项目配置

<dependencies>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.0</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

核心的依赖 mybatis-spring-boot-starter ,至于版本选择,到mvn仓库中,找最新的

另外一个不可获取的就是db配置信息, appliaction.yml

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password:

2. 数据库表

用于测试的数据库

CREATE TABLE `money` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL DEFAULT '' COMMENT '用户名',
  `money` int(26) NOT NULL DEFAULT '0' COMMENT '钱',
  `is_deleted` tinyint(1) NOT NULL DEFAULT '0',
  `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=551 DEFAULT CHARSET=utf8mb4;

II. ResultMap & ResultType介绍

1. 使用区别

ResultMap:

  • 当数据库的字段与定义的实体对象不一致时(如下划线转驼峰,命名不一致等)通过 <ResultMap> 标签来定义映射关系,然后在sql查询标签中,通过 resultMap 来指定

ResultType:

  • db中的字段直接与实体对象进行映射时,选择ResultType,其value为实体类的全路径

2. 实例演示

注意上面的表结构,是以下划线的命名方式,接下来定义一个驼峰格式的实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MoneyPo {
    private Integer id;

    private String name;

    private Long money;

    private Integer isDeleted;

    private Timestamp createAt;

    private Timestamp updateAt;
}

基于上面这个case,很明显当我们使用查询时,返回结果就需要做一个映射,此时就可以使用 <ResultMap> 方式

<resultMap id="BaseResultMap" type="com.git.hui.boot.mybatis.entity.MoneyPo">
    <id column="id" property="id" jdbcType="INTEGER"/>
    <result column="name" property="name" jdbcType="VARCHAR"/>
    <result column="money" property="money" jdbcType="INTEGER"/>
    <result column="is_deleted" property="isDeleted" jdbcType="TINYINT"/>
    <result column="create_at" property="createAt" jdbcType="TIMESTAMP"/>
    <result column="update_at" property="updateAt" jdbcType="TIMESTAMP"/>
</resultMap>
<sql id="money_po">
  id, name, money, is_deleted, create_at, update_at
</sql>

<select id="queryByName"  parameterType="java.lang.String" resultMap="BaseResultMap">
    select * from money where `name` = #{name}
</select>

注意上面的select标签,通过resultMap来实现表字段与实体对象的转换关系(通过 <resultMap> 标签内的 <result> 来定义映射关系)

除了使用上面这种方式之外,也可以通过resultType来指定返回结果为Map,同样是可行的

<select id="queryMapsByName"  parameterType="java.lang.String" resultType="java.util.HashMap">
    select * from money where `name` = #{name}
</select>

对应的mapper接口内容如下

@Mapper
public interface MoneyMapperV4 {
    /**
     * int类型,最终的sql中参数替换的也是int
     * @param name
     * @return
     */
    List<MoneyPo> queryByName(@Param("name") String name);

    /**
     * 注意返回结果
     *
     * @param name
     * @return
     */
    List<HashMap<String, Object>> queryMapsByName(@Param("name") String name);
}

3. 测试验证

@Autowired
private MoneyMapperV4 moneyMapperV4;

public void testResQuery() {
    List<MoneyPo> list = moneyMapperV4.queryByName("一灰灰blog");
    System.out.println(list);
    List<HashMap<String, Object>> mapList = moneyMapperV4.queryMapsByName("一灰灰blog");
    System.out.println(mapList);
}

输出结果如下

[MoneyPo(id=1, name=一灰灰blog, money=100, isDeleted=0, createAt=2019-04-18 17:01:40.0, updateAt=2019-04-18 17:01:40.0, cnt=null, bank=null)]
[{is_deleted=false, money=100, name=一灰灰blog, update_at=2019-04-18 17:01:40.0, id=1, create_at=2019-04-18 17:01:40.0}]

请注意上面的输出,返回结果是Map时,key和db中的字段名完全一致

其次也可以从Mapper接口的返回定义上可以看出,虽然最终返回的是列表,但是我们定义的resultMap, resultType,都是对应的单个实体的映射关系

如何理解上面这句话呢?

  • 如果上面的sql改成只获取id,那么返回结果应该是定义为longe而不是List
<select id="queryIdByName" resultType="long">
    select id from money where `name` = #{name}
</select>

对应的mapper接口如下

List<Long> queryIdByName(String name);

4. 小结

ResultMap

  • 当希望实现sql返回的对象与项目中的实体类实现关联映射时,可以考虑通过resumtMap来实现

ResultType

  • 指定返回实体类型,可以是基础对象(long, int…) 也可以是Map,当指定一个具体的POJO时,db的表字段与pojo的field全名匹配映射

III. 不能错过的源码和相关知识点

0. 项目

系列博文:

1. 微信公众号: 一灰灰Blog

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

打赏 如果觉得我的文章对您有帮助,请随意打赏。