Mybatis从小白到小黑(四)MyBatis实现复杂环境的Sql查询

简介: 在前面的学习中,我们差不多把Mybatis的基本增删改查、配置文件的配置都讲解了一遍,但是在实际的开发中我们编写的sql不会那么简单,今天就来模拟复杂环境的Sql查询

听说微信搜《Java鱼仔》会让技术提高更快哦


在前面的学习中,我们差不多把Mybatis的基本增删改查、配置文件的配置都讲解了一遍,但是在实际的开发中我们编写的sql不会那么简单,今天就来模拟复杂环境的Sql查询


(一)resultMap结果映射


resultMap 元素是 MyBatis 中最重要最强大的元素,我们之前所写的sql语句,返回值都是简单的基本数据类型或者某一个实体类,比如下面这段sql返回的就是最简单的User类型。

<selectid="getUserById"resultType="com.javayz.pojo.User"parameterType="int">    select * from user where id=#{id};
</select>

现在思考一下下面这种情况,如果实体类中定义的某一个字段和数据库中的字段不一致怎么办

publicclassUser {
privateintid;
privateStringlastname;
//.....}

比如我定义了一个User类,包含id和lastname两个属性,而数据库中这两个字段的名字为id和name。此时再执行查询时结果如下:lastname这个字段直接为null


网络异常,图片无法展示
|


这时候我们就可以使用resultMap来解决这个问题,resultMap可以讲数据库中的字段映射到实体类上。column代表数据库中的字段名,properties代表实体类中的字段名,通过映射之后Mybatis就可以找到对应的字段。

<resultMapid="UserMap"type="User"><!--column代表数据库中的字段名,properties代表实体类中的字段名--><resultcolumn="id"property="id"/><resultcolumn="name"property="lastname"/></resultMap><selectid="getUserById"resultMap="UserMap"parameterType="int">    select id,name from user where id=#{id};
</select>

ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。


(二)复杂环境下的resultMap使用


在实际的应用场景中,我们会遇到很多比较复杂的业务逻辑,这里resultMap的优势才会被放大。因此我们通过一个案例来实现复杂环境的查询。


//创建教室表
createtable classroom
(  id intnotnull AUTO_INCREMENT,  classname VARCHAR(40)notnull,  PRIMARY KEY (id))//创建学生表
createtable student
(  id intnotnull AUTO_INCREMENT,  name VARCHAR(40)notnull,  classid intnotnull,  PRIMARY KEY (id),  FOREIGN key (classid) REFERENCES classroom(id))//创建一些数据
insertinto classroom VALUES(1,'101班')insertinto classroom VALUES(2,'102班')insertinto student VALUES(1,'Amy',1);insertinto student VALUES(2,'Bob',1);insertinto student VALUES(3,'javayz',1);

在Java的实体类代码中分别建立Student和ClassRoom的类

publicclassStudent {
privateintid;
privateStringname;
privateClassRoomclassRoom;
//省略构造方法、get、set、toString//务必给出无参构造方法}

ClassRoom 类

publicclassClassRoom {
privateintid;
privateStringclassname;
//省略构造方法、get、set、toString//务必给出无参构造方法}

2.1 多对一查询(association)


多对一查询在上面这个案例中表现为多个学生在一个教实中,因此这里的Student类中的第三个变量我们设置为ClassRoom类。


现在我们通过两种方式进行多对一查询:


在mapper路径下创建StudentMapper和studentMapper.xml

其中StudentMapper接口定义一个查询方法:


publicinterfaceStudentMapper {
List<Student>selectAllStudent();
}

查询方法一:通过类似嵌套子查询的方式查询:

<selectid="selectAllStudent"resultMap="StudentAndClassRoom">    select * from student
</select><resultMapid="StudentAndClassRoom"type="Student"><resultproperty="id"column="id"/><resultproperty="name"column="name"/><!--对于复杂类型,对象使用association处理,集合使用collection--><associationproperty="classRoom"column="classid"javaType="ClassRoom"select="getClassRoom"></association></resultMap><selectid="getClassRoom"resultType="ClassRoom">    select * from classroom where id = #{classid}
</select>

首先通过 select * from student 语句查询到所有数据,返回类型通过resultMap进行映射,id和name字段属于基本数据类型字段不需要改动,由于classRoom是一个对象方法,因此需要用association 进行处理,实体类中的属性名为classRoom,与Student表进行连接的字段是classid,Java类是ClassRoom,通过这几个属性,继续使用select查询。

所以上面一段代码总结下来就是两句话:


1、查询student表。


2、通过查询出来的classid值查询classRoom表。


通过测试类测试结果:


@TestpublicvoidtestSelect(){
SqlSessionsqlSession=MybatisUtils.getSqlSession();
StudentMappermapper=sqlSession.getMapper(StudentMapper.class);
List<Student>students=mapper.selectAllStudent();
System.out.println(students);
}

结果如下:

[Student{id=1, name='Amy', classRoom=ClassRoom{id=1, classname='101班'}}, 
Student{id=2, name='Bob', classRoom=ClassRoom{id=1, classname='101班'}},
Student{id=3, name='javayz', classRoom=ClassRoom{id=1, classname='101班'}}]

查询方法二:结果嵌套查询

<selectid="selectAllStudent"resultMap="StudentAndClassRoom">    select s.id sid,s.name sname,c.id cid,c.classname cname
    from student s,classroom c
    where s.classid=c.id
</select><resultMapid="StudentAndClassRoom"type="Student"><resultproperty="id"column="sid"/><resultproperty="name"column="sname"/><associationproperty="classRoom"javaType="ClassRoom"><resultproperty="id"column="cid"/><resultproperty="classname"column="cname"/></association></resultMap>

我个人比较喜欢结果嵌套查询,所有的sql语句写在select语句中,根据结果要返回的值在resultMap中填写对应的数据。


结果与第一种方式相同。


2.2 一对多查询(collection)


修改一下之前的两个实体类,来实现一对多的查询,每个教室里有多个学生:

publicclassStudent {
privateintid;
privateStringname;
privateintclassId;
//省略get、set、toString方法//务必给出无参构造方法}
publicclassClassRoom {
privateintid;
privateStringclassname;
privateList<Student>students;
//省略get、set、toString方法//务必给出无参构造方法}  

接着编写Mapper接口和对应的Mapper.xml

publicinterfaceClassRoomMapper {
List<ClassRoom>getClassRoomByid(@Param("id") intid);
}

在这里我只介绍结果嵌套查询的方式。先通过sql查询出字段信息,再通过resultMap进行展示。

<?xmlversion="1.0" encoding="UTF8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.javayz.mapper.ClassRoomMapper"><selectid="getClassRoomByid"resultMap="ClassRoomAndStudent"parameterType="int">        select c.id cid,c.classname cname,s.id sid,s.name sname,s.classid classid
        from student s,classroom c
        where s.classid=c.id and c.id=#{id}
</select><resultMapid="ClassRoomAndStudent"type="ClassRoom"><resultproperty="id"column="cid"/><resultproperty="classname"column="cname"/><!--对于集合属性,需要使用collection来实现--><collectionproperty="students"ofType="Student"><resultproperty="id"column="sid"/><resultproperty="name"column="sname"/><resultproperty="classId"column="classid"/></collection></resultMap></mapper>

需要注意几个点,对于集合属性,我们需要使用collection。这里的集合属性中用到了ofType字段,该字段表示集合泛型中所使用的泛型对象类型。


(三)总结


到这里为止,Mybatis的各种查询以及配置用法都讲完了,对于复杂类型,注意以下几点:


1、对象的关联使用association,集合的关联使用collection。


2、官网的resultMap中还有两个参数没有使用:


网络异常,图片无法展示
|


首先讲一下constructor ,constructor主要是用来配置构造方法,默认情况下mybatis会调用实体类的无参构造方法创建一个实体类,如果在实体类中配置了有参构造方法而没有配无参构造,就会报错,此时可用constructor 注入构造方法。


discriminator 鉴别器,可以通过case的值来决定使用哪个resultMap。



相关文章
|
13天前
|
SQL 存储 人工智能
Vanna:开源 AI 检索生成框架,自动生成精确的 SQL 查询
Vanna 是一个开源的 Python RAG(Retrieval-Augmented Generation)框架,能够基于大型语言模型(LLMs)为数据库生成精确的 SQL 查询。Vanna 支持多种 LLMs、向量数据库和 SQL 数据库,提供高准确性查询,同时确保数据库内容安全私密,不外泄。
78 7
Vanna:开源 AI 检索生成框架,自动生成精确的 SQL 查询
|
20天前
|
SQL Java
使用java在未知表字段情况下通过sql查询信息
使用java在未知表字段情况下通过sql查询信息
34 8
|
1月前
|
SQL 缓存 Java
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
本文详细介绍了MyBatis的各种常见用法MyBatis多级缓存、逆向工程、分页插件 包括获取参数值和结果的各种情况、自定义映射resultMap、动态SQL
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
|
27天前
|
SQL 安全 PHP
PHP开发中防止SQL注入的方法,包括使用参数化查询、对用户输入进行过滤和验证、使用安全的框架和库等,旨在帮助开发者有效应对SQL注入这一常见安全威胁,保障应用安全
本文深入探讨了PHP开发中防止SQL注入的方法,包括使用参数化查询、对用户输入进行过滤和验证、使用安全的框架和库等,旨在帮助开发者有效应对SQL注入这一常见安全威胁,保障应用安全。
47 4
|
1月前
|
SQL 监控 关系型数据库
SQL语句当前及历史信息查询-performance schema的使用
本文介绍了如何使用MySQL的Performance Schema来获取SQL语句的当前和历史执行信息。Performance Schema默认在MySQL 8.0中启用,可以通过查询相关表来获取详细的SQL执行信息,包括当前执行的SQL、历史执行记录和统计汇总信息,从而快速定位和解决性能瓶颈。
|
1月前
|
SQL 存储 缓存
如何优化SQL查询性能?
【10月更文挑战第28天】如何优化SQL查询性能?
107 10
|
1月前
|
SQL 关系型数据库 MySQL
|
21天前
|
SQL Java 数据库连接
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
|
2月前
|
SQL 数据库 开发者
功能发布-自定义SQL查询
本期主要为大家介绍ClkLog九月上线的新功能-自定义SQL查询。
|
1月前
|
SQL 关系型数据库 MySQL
mysql编写sql脚本:要求表没有主键,但是想查询没有相同值的时候才进行插入
mysql编写sql脚本:要求表没有主键,但是想查询没有相同值的时候才进行插入
33 0