JavaWeb进阶之路:MyBatis-结果集映射

1,471 阅读2分钟

1. 思考

在上篇文章 JavaWeb进阶之路:MyBatis-CURD(增删改查) 中,我们使用 Mybatis 对数据库做了增删改查的操作,相信大家对 Mybatis 的增删改查有了一定的了解。但在我们真实的业务需求中,数据库的字段名和我们项目中实体类的属性名不一致,这个时候就会出现查询出来的数据为 NUll 。这是为什么呢?如何解决这个问题?

那其实解决这个问题有 2 种方式,一种是用 sql 语句中的别名 来解决字段名和属性名不一致。还有一种就是接下来我们要介绍的 ResultMap 结果集映射。

2. 简介

resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap 能够代替实现同等功能的数千行代码。ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。

简单的 resultMap 用法,例如:

<!-- mybatis-config.xml 中 -->
<configuration>
    ...
    <typeAliases>
        <typeAlias type="com.lmx.demo3.pojo.User" alias="User"/>
    </typeAliases>
    ...
</configuration>

<!-- UserMapper.xml 中 -->
<mapper namespace="com.lmx.demo3.mapper.UserMapper">
    
    <!-- id全局唯一标识名, type 返回类型 -->
    <resultMap id="UserMap" type="User">
        <!-- 主键 -->
        <id column="id" property="id"/>
        <!-- column 数据库表名, property 实体类属性名 -->
        <result column="name" property="account"/>
        <result column="password" property="password"/>
    </resultMap>
    
    <select id="selectUserById" parameterType="int" resultMap="UserMap">
        select * from user where id = #{id};
    </select>
    
</mapper>

3. 实践

3.1 问题

数据库的字段名和 Java 实体类的属性名不一致,导致查询结果属性值为 NULL。

3.2 搭建环境

数据库:

数据库

Java 实体类:

package com.lmx.demo3.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private long id;
	// 对应数据库中的 name 字段
    private String account;
    private String password;

}

UserMapper 接口类:

package com.lmx.demo3.mapper;

import com.lmx.demo3.pojo.User;

public interface UserMapper {

    User selectUserById(int id);
    
}

UserMapper.xml sql 映射文件:

<?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.lmx.demo3.mapper.UserMapper">

    <select id="selectUserById" parameterType="int" resultType="User">
        select * from user where id = #{id};
    </select>
    
</mapper>

测试类:

package com.lmx.test.mapper;

import com.lmx.demo3.mapper.UserMapper;
import com.lmx.demo3.pojo.User;
import com.lmx.demo3.util.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

public class UserMapperTest {

    @Test
    public void selectUserById() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.selectUserById(1);
        System.out.println(user);
        sqlSession.close();
    }

}

输出结果:

错误结果

分析:

  • select * from user where id = #{id} 可以看做

    select id,name,password from user where id = #{id}

  • Mybatis 会根据这些查询的列名(会将列名转化为小写,数据库不区分大小写),去对应的实体类中查找相应列名的 set 方法设值,由于找不到 setName() 方法, 所以 account 返回 null ;【自动映射】

3.3 解决问题

我们可以通过强大 resultMap 解决问题:

只需要对 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.lmx.demo3.mapper.UserMapper">
    <!-- 第一种方式 -->
    <!-- id全局唯一标识名, type 返回类型 -->
    <resultMap id="UserMap" type="User">
        <!-- 主键 -->
        <id column="id" property="id"/>
        <!-- column 数据库表名, property 实体类属性名 -->
        <result column="name" property="account"/>
        <result column="password" property="password"/>
    </resultMap>
    
    <!-- 第二种方式:只需要写匹配不上的列名和属性名-->
<!--<resultMap id="UserMap" type="User">-->
<!--	<result column="name" property="account"/>-->
<!--</resultMap>-->
    
    <select id="selectUserById" parameterType="int" resultMap="UserMap">
        select * from user where id = #{id};
    </select>
</mapper>

运行结果:

运行结果

4. 结尾

如果这个世界总是这么简单就好了。但肯定不是的,数据库中,存在一对多,多对一的情况,那这个时候我们现在所学的 resultMap 显然是不够的。那怎么办?不用担心, Mybatis 提供了高级结果映射,如果有兴趣的话可以去官方说明文档: 结果映射 学习一下,后续我也会专门写一篇文章介绍。