Mybatis 普通结果映射(ResultMap)

上一篇内容我们使用了Mybatis去查询数据库中的一条数据,本篇我们在上一篇的基础上对结果映射进行详细介绍一下。

如果您对查询数据不太了解,可以参考:
Mybatis查询一条数据icon-default.png?t=N7T8https://blog.csdn.net/m1729339749/article/details/132469672

 一、准备数据

 这里我们直接使用脚本初始化数据库中的数据

-- 如果数据库不存在则创建数据库
CREATE DATABASE IF NOT EXISTS demo DEFAULT CHARSET utf8;
-- 切换数据库
USE demo;
-- 创建用户表
CREATE TABLE IF NOT EXISTS T_USER(
  ID INT PRIMARY KEY,
  USERNAME VARCHAR(32) NOT NULL,
  AGE INT NOT NULL 
);
-- 插入用户数据
INSERT INTO T_USER(ID, USERNAME, AGE)
VALUES(1, '张三', 20),(2, '李四', 22),(3, '王五', 24);

创建了一个名称为demo的数据库;并在库里创建了名称为T_USER的用户表并向表中插入了数据

二、定义实体类

在cn.horse.demo包下创建UserInfo实体类,里面包含了一个无参数构造方法和一个带有两个参数的构造方法;

为了方便打印用户的信息这里重写了ToString()方法

package cn.horse.demo;

public class UserInfo {
    private Integer userId;
    private String name;
    private Integer age;

    public UserInfo() { }
    public UserInfo(int userId, String name) {
        this.userId = userId;
        this.name = name;
    }

    @Override
    public String toString() {
        StringBuilder result = new StringBuilder();
        result.append('[');
        result.append("userId: " + this.userId);
        result.append(", ");
        result.append("name: " + this.name);
        result.append(", ");
        result.append("age: " + this.age);
        result.append(']');
        return result.toString();
    }
}

三、配置Mapper文件

这里我在resources下创建了一个demo3的目录,并在目录下创建了一个UserInfoMapper1.xml的配置文件。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.horse.demo.UserInfoMapper1">

    <select id="findById" resultType="cn.horse.demo.UserInfo">
        SELECT *
        FROM T_USER
        WHERE ID = #{id}
    </select>
</mapper>

这里名称空间指定为cn.horse.demo.UserInfoMapper1

查询标签的编号指定为findById, 返回类型为cn.horse.demo.UserInfo,SQL语句为根据ID查询用户信息

四、引入Mapper配置

Mapper配置完成后,并没有生效;需要在mybatis-config.xml文件中配置完成后才能生效;

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="jdbc:mysql://${ip}:${port}/${database}?useUnicode=true&amp;useSSL=false&amp;characterEncoding=utf8"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="demo3/UserInfoMapper.xml" />
    </mappers>
</configuration>

五、查询数据

// 读取mybatis配置文件
InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream("mybatis-config.xml");
// 根据配置创建SqlSession工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
        .build(inputStream);

SqlSession sqlSession = null;
try {
    // 创建SqlSession
    sqlSession = sqlSessionFactory.openSession();
    // 根据用户编号查询一条用户信息
    UserInfo userInfo = sqlSession.selectOne("cn.horse.demo3.UserInfoMapper.findById", 2);
    System.out.println(userInfo);
} finally {
    // 关闭会话
    if(Objects.nonNull(sqlSession)) {
        sqlSession.close();
    }
}

代码执行的结果如下:

发现userId, name没有值,只有age字段有值

分析原因

上一篇我们提到过,查询出来的数据转换成结果类型对象需要满足两个条件

  1. 结果类型提供无参数的构造方法
  2. 查询的列需要与结果类型的字段一一对应

原因就在于从表中查询的字段有ID, USERNAME, AGE;而结果类型的字段只有age能够对应上,导致userId, name字段无法绑定值。

解决方法

  1. 查询表数据时指定别名
  2. 使用ResultMap进行结果映射

六、查询表数据指定别名

这里我们在resources的demo目录下新建UserInfoMapper2配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.horse.demo.UserInfoMapper2">

    <select id="findById" resultType="cn.horse.demo.UserInfo">
        SELECT
            ID userId,
            USERNAME name,
            AGE age
        FROM T_USER
        WHERE ID = #{id}
    </select>
</mapper>

SQL语句中我们为表中的字段指定了别名,保证别名与返回类型的字段一致;

另外我们还需要在mybatis-config.xml中引入配置文件

<mapper resource="demo/UserInfoMapper2.xml" />

测试:

findById("cn.horse.demo.UserInfoMapper2.findById", 2);

执行查询数据的代码,结果如下:

发现userId, name字段的值也查询出来了

七、使用ResultMap进行结果映射

这里我们使用ResultMap标签进行结果映射,并为select标签指定结果映射的resultMap

1、使用无参数的构造方法创建映射类型对象

这里我们在resources的demo目录下新建UserInfoMapper3配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.horse.demo.UserInfoMapper3">

    <resultMap id="userInfoMap" type="cn.horse.demo.UserInfo">
        <result column="USERNAME" property="name" />
        <result column="ID" property="userId" />
        <result column="AGE" property="age" />
    </resultMap>

    <select id="findById" resultMap="userInfoMap">
        SELECT *
        FROM T_USER
        WHERE ID = #{id}
    </select>
</mapper>

(1)使用resultMap建立查询列与映射类型字段的映射

resultMap标签:id是编号,相同命名空间下不同重复, type是映射类型

result标签: column是查询的列,property是映射类型的字段;通过指定column,property完成数据库列到映射类型字段的对应关系

(2)使用resultMap属性指定select标签使用的结果映射

原来select标签中使用的resultType属性修改成了resultMap属性,并使用定义的resultMap标签的属性id作为resultMap属性的值

由于这里只是指定了列与字段的对应关系,映射类型对象的创建则使用无参数的构造方法

 另外我们还需要在mybatis-config.xml中引入配置文件

<mapper resource="demo/UserInfoMapper3.xml" />

测试:

findById("cn.horse.demo.UserInfoMapper3.findById", 2);

执行查询数据的代码,结果如下:

发现userId, name字段的值也查询出来了

2、使用带有两个参数的构造方法创建映射类型对象(不建议使用)

这里我们在resources的demo目录下新建UserInfoMapper4配置文件  

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.horse.demo.UserInfoMapper4">

    <resultMap id="userInfoMap" type="cn.horse.demo.UserInfo">
        <constructor>
            <arg column="USERNAME" name="name" />
            <arg column="ID" name="userId" />
        </constructor>
        <result column="AGE" property="age" />
    </resultMap>

    <select id="findById" resultMap="userInfoMap">
        SELECT *
        FROM T_USER
        WHERE ID = #{id}
    </select>
</mapper>

constructor标签:代表使用指定的构造方法创建映射类型对象,具体使用哪个构造方法会根据参数的个数、类型、名称进行筛选,与参数的顺序无关;这里使用了带有两个参数的构造方法,构造方法的参数包含name和userId。

arg标签:代表的是构造方法参数的映射,column代表的是查询的列,name代表的是构造方法的参数名称。

另外我们还需要在mybatis-config.xml中引入配置文件

<mapper resource="demo/UserInfoMapper4.xml" />

测试:

findById("cn.horse.demo.UserInfoMapper4.findById", 2);

执行查询数据的代码,结果如下:

发现userId, name字段的值也查询出来了

 可能出现的问题

Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException: 
### Error building SqlSession.
### The error may exist in demo3/UserInfoMapper.xml
### The error occurred while processing mapper_resultMap[userInfoMap]
### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. Cause: org.apache.ibatis.builder.BuilderException: Error in result map 'cn.horse.demo3.UserInfoMapper.userInfoMap'. Failed to find a constructor in 'cn.horse.demo3.UserInfo' by arg names [name, userId]. There might be more info in debug log.
	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
	at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:80)
	at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:64)
	at cn.horse.demo3.Main.main(Main.java:16)
Caused by: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. Cause: org.apache.ibatis.builder.BuilderException: Error in result map 'cn.horse.demo3.UserInfoMapper.userInfoMap'. Failed to find a constructor in 'cn.horse.demo3.UserInfo' by arg names [name, userId]. There might be more info in debug log.
	at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:121)
	at org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(XMLConfigBuilder.java:99)
	at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:78)
	... 2 more
Caused by: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. Cause: org.apache.ibatis.builder.BuilderException: Error in result map 'cn.horse.demo3.UserInfoMapper.userInfoMap'. Failed to find a constructor in 'cn.horse.demo3.UserInfo' by arg names [name, userId]. There might be more info in debug log.
	at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:120)
	at org.apache.ibatis.builder.xml.XMLMapperBuilder.parse(XMLMapperBuilder.java:92)
	at org.apache.ibatis.builder.xml.XMLConfigBuilder.mapperElement(XMLConfigBuilder.java:373)
	at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:119)
	... 4 more
Caused by: org.apache.ibatis.builder.BuilderException: Error in result map 'cn.horse.demo3.UserInfoMapper.userInfoMap'. Failed to find a constructor in 'cn.horse.demo3.UserInfo' by arg names [name, userId]. There might be more info in debug log.
	at org.apache.ibatis.mapping.ResultMap$Builder.build(ResultMap.java:132)
	at org.apache.ibatis.builder.MapperBuilderAssistant.addResultMap(MapperBuilderAssistant.java:213)
	at org.apache.ibatis.builder.ResultMapResolver.resolve(ResultMapResolver.java:47)
	at org.apache.ibatis.builder.xml.XMLMapperBuilder.resultMapElement(XMLMapperBuilder.java:285)
	at org.apache.ibatis.builder.xml.XMLMapperBuilder.resultMapElement(XMLMapperBuilder.java:252)
	at org.apache.ibatis.builder.xml.XMLMapperBuilder.resultMapElements(XMLMapperBuilder.java:244)
	at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:116)

 造成的原因是编译时未保留方法的参数名

解决方法

 在pom文件中新增编译参数

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>${maven.compiler.source}</source>
                <target>${maven.compiler.target}</target>
                <compilerArgs>
                    <arg>-parameters</arg>
                </compilerArgs>
                <encoding>${project.build.sourceEncoding}</encoding>
            </configuration>
        </plugin>
    </plugins>
</build>

其中-parameters参数可以在编译时保留方法的参数名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值