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 提供了高级结果映射,如果有兴趣的话可以去官方说明文档: 结果映射 学习一下,后续我也会专门写一篇文章介绍。