resultMap映射学习

本文详细探讨了MyBatis的resultMap映射机制,包括resultMap的概念、实际使用示例、高级映射技巧,以及如何处理结果集的合并和主键合并策略。通过实例展示了resultMap相比于resultType的灵活性,帮助理解如何自定义映射规则。
摘要由CSDN通过智能技术生成

resultMap映射学习

博客作为个人学习笔记,随着学习深入更新。

接上一篇resultType映射学习

(1)Question:resultMap是什么

resultMap与resultType类似,也是MyBatis框架中的一种映射方式。但是与resultMap不同的是,其映射规则由用户自己定义,比resultType更加灵活。不过还有很重要的一个方面就是,在返回数据的形式上,resultMap可以去除不必要的冗余。

(2)resultMap实际使用

数据库中有这样一张表school

class_nameteachermobilenameid
六年一班阿福13131313131小夫1
六年一班阿福13131313131大熊2
六年一班阿福13131313131静香3

需求:客户端需要读取到六年一班所有学生的姓名与学号

xml文件关键语句如下

<mapper namespace="com.test.MybatisDao">
<resultMap id="getStudentMap" type="com.test.Class">
<id property="id" column="id"/>
<result property="name" column="name"/>
</resultMap>

<select id="get" resultMap="getStudentMap">
    select id, name from school
</select>

这里明确一点,property为映射结果中的属性,而column是查询回结果集中的列名

映射结果集为

class Class {
    private Integer id;
    
    private String name;
}

执行sql语句后,可以得到这样一个查询结果集

idname
1小夫
2大熊
3静香

该结果集经过resultMap映射后,返回前端的形式如下

[
    {
        "id": 1,
        "name": "小夫"
    },
    {
        "id": 2,
        "name": "大熊"
    },
    {
        "id": 3,
        "name": "静香"
    }
]

这是一个简单的结果集映射,如果要深入探究resultMap映射,那么可以做一个较为复杂的映射。

高级映射

需求:客户需要知道查询班级的老师、老师的号码以及所有学生的信息

修改school表如下

class_nameteachermobilenameid
六年一班阿福13131313131小夫1
六年一班阿福13131313131大熊2
六年一班阿福13131313131静香3
六年二班特鲁13131313132胖虎1
六年二班特鲁13131313132小新2
六年三班老爹13131313133小玉1

xml关键语句如下

<resultMap id="studentMap" type="com.thingcom.mybatis.Class">
    <id property="className" column="class_name"/>
    <result property="teacher" column="teacher"/>
    <result property="mobile" column="mobile"/>
    <collection property="student" ofType="com.thingcom.mybatis.Student">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
    </collection>
</resultMap>
    
<select id="get" resultMap="getStudentMap">
    select class_name, teacher, mobile, id, name from school 
    where class_name = #{className}
</select>

映射结果集如下

@Data
class Class {
    private String className;

    private String teacher;

    private String mobile;

    private Student student;
}

@Data
class Student {
    private Integer id;

    private String name;
}

结果查询返回这样一张表

class_nameteachermobileidname
六年一班阿福131313131311小夫
六年一班阿福131313131312大熊
六年一班阿福131313131313静香

返回前端的结果集如下

[
    {
        "className": "六年一班",
        "teacher": "阿福",
        "mobile": "13131313131",
        "student": {
            "id": 3,
            "name": "静香"
        }
    }
]

可以看到,结果并不是我们期望的,从数据库查询的内容没有问题,问题一定是出现在resultMap映射上。

(3)查看result映射机制

首先在说明result是如何映射时,我们要先了解一个规范----JDBC

JDBC(Java Database Connectivity)是用于连接数据库与java的一道桥梁,由一些java编写的类和接口组成,使用spring框架的可以在yml文件中看到这一句

driver-class-name: com.mysql.cj.jdbc.Driver

这是使用jdbc驱动与数据库连接
在这里插入图片描述
值得关注的是在jdbc中有一个resultSet接口,其中有一个next方法可以用来遍历resultSet结果集,即resultSet.next()每一次执行都会取结果集中的下一行,该方法返回类型为boolean。此时可以通过getString()方法获取指定列的值,这样就可以将结果集中的值取出,在处理完结果集后,jdbc会释放资源,此时ResultSet结果集就被清空。

DBUtil dbUtil = new DBUtil();
Connection con = dbUtil.getconnection();
String sql = "select id from table"
PreparedStatement psta = con.prepareStatement(sql);
ResultSet rs  = new psta.executeQuery();
while(rs.next()) {
    int id = rs.getString("id");   
    int id = rs.getString(1);   
    Class test = new Class();
    test.setId(id);
}

getString方法中的参数可以是列的位置,也可以是列的键,在ResultSet中结果集的列是从1开始计算的。在这里可以看出,如果存储结果集的类不是一个list的话,就会导致数据被覆盖,显示的数据就会是最新的那一条。

在jdbc中只需要加上这一句即可

testList.add(test);

mybatis将jdbc封装后这种思想也是一样,映射规则也是按行取出,因此将映射结果集代码修改如下

@Data
class Class {
    private String className;

    private String teacher;

    private String mobile;

    private List<Student> student;
}

从映射结果如下

[
    {
        "className": "六年一班",
        "teacher": "阿福",
        "mobile": "13131313131",
        "student": [
            {
                "id": 1,
                "name": "小夫"
            },
            {
                "id": 2,
                "name": "大熊"
            },
            {
                "id": 3,
                "name": "静香"
            }
        ]
    }
]

此时回到resultType上,按照这个想法,假设resultType要处理这样的映射,需不需要将第二层封装设置为List呢?

答案是这样处理回导致无法映射进结果集

xml配置

<select id="get" resultType="com.thingcom.mybatis.Class">
        select class_name "className", teacher, mobile, id "student.id", name "student.name" from school
        where class_name = #{className}
</select>

返回结果集

[
    {
        "className": "六年一班",
        "teacher": "阿福",
        "mobile": "13131313131",
        "student": null
    },
    {
        "className": "六年一班",
        "teacher": "阿福",
        "mobile": "13131313131",
        "student": null
    },
    {
        "className": "六年一班",
        "teacher": "阿福",
        "mobile": "13131313131",
        "student": null
    }
]

可以看到,第二层的信息没有映射进结果集,根据jdbc的思想,Class类会创建一个对象去取className、teacher、mobile的值,最后通过list.add方法处理;Student类也会创建一个对象取id、name,但是问题在于这个对象是取不到id和name的值的,因为在处理sql语句中,将id、name重命名为student.id、student.name了。因此resultType无法做到像resultMap那样灵活。

(4)合并

对比resultMap和resultType返回结果集,可以发现resultMap会把相同的字段合并。既然在jdbc那里了解到result结果集映射是按行返回的。那么可以想到,在从resultSet中取回信息时,resultMap会根据键值来判断可不可以合并,没有设置主键则所有键值相同则判断为可以合并,设置主键,会根据主键值来判断。所以在设置映射时设置主键可以减少映射时间。

(5)再加一层

现在将表修改如下

class_nameteachermobilenameidhome_name
六年一班阿福13131313131小夫1a
六年一班阿福13131313131大熊2b
六年一班阿福13131313131静香3c
六年二班特鲁13131313132胖虎1d
六年二班特鲁13131313132小新2e
六年三班老爹13131313133小玉1f

需求与(3)相同

xml修改如下

    <resultMap id="studentMap" type="com.thingcom.mybatis.Class">
        <id property="className" column="class_name"/>
        <result property="teacher" column="teacher"/>
        <result property="mobile" column="mobile"/>
        <collection property="student" ofType="com.thingcom.mybatis.Student">
            <id property="id" column="id"/>
            <result property="name" column="name"/>
            <collection property="home" ofType="com.thingcom.mybatis.Home">
                <id property="homeName" column="home_name"/>
            </collection>
        </collection>
    </resultMap>

    <select id="get" resultMap="studentMap">
        select class_name , teacher, mobile, id, name, home_name from school
        where class_name = #{className}
    </select>

添加映射结果集

@Data
class Student {
    private Integer id;

    private String name;

    private Home home;
}
@Data
class Home{
    private String homeName;
        }

映射结果如下

[
    {
        "className": "六年二班",
        "teacher": "特鲁",
        "mobile": "13131313132",
        "student": [
            {
                "id": 1,
                "name": "胖虎",
                "home": {
                    "homeName": "d"
                }
            },
            {
                "id": 2,
                "name": "小新",
                "home": {
                    "homeName": "e"
                }
            }
        ]
    }
]

了解了映射原理之后,再写也就简单多了

参考博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值