MyBatis复杂Sql查询实现示例介绍

 更新时间:2022年12月29日 10:02  点击:204 作者:一个双子座的Java攻城狮

resultMap 结果映射

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

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

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

public class User {
    private int id;
    private String lastname;
    //.....
}

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

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

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

准备数据

接下来结合学生与教室的案例模拟复杂场景:

//创建教室表
create table classroom
(
id int not null AUTO_INCREMENT,
classname VARCHAR(40) not null,
PRIMARY KEY (id)
);
//创建学生表
create table student
(
id int not null AUTO_INCREMENT,
name VARCHAR(40) not null,
classid int not null,
PRIMARY KEY (id),
FOREIGN key (classid) REFERENCES classroom(id)
);
//创建一些数据
insert into classroom VALUES (1,'101班');
insert into classroom VALUES (2,'102班');
insert into student VALUES(1,'Amy',1);
insert into student VALUES(2,'Bob',1);
insert into student VALUES(3,'javayz',1);

多对一查询(association)

现在要实现一个多对一的查询需求,查询所有的学生,并将每个学生所在的教室包含在内。由于现在的情况是多学生和教室的关系是多对一,因此在构建实体类时在 Student 类上要加上 ClassRoom 变量。

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

package com.cn.pojo;
public class ClassRoom {
    private int id;
    private String classname;
    public ClassRoom(){}
    public int getId() {
        return id;
    }
    public String getClassname() {
        return classname;
    }
    public void setId(int id) {
        this.id = id;
    }
    public void setClassname(String classname) {
        this.classname = classname;
    }
    @Override
    public String toString() {
        return "ClassRoom{" +
                "id=" + id +
                ", classname='" + classname + '\'' +
                '}';
    }
}

package com.cn.pojo;
public class Student {
    private int id;
    private String name;
    private ClassRoom classRoom;
    public Student(){}
    public int getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    public ClassRoom getClassRoom() {
        return classRoom;
    }
    public void setId(int id) {
        this.id = id;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setClassRoom(ClassRoom classRoom) {
        this.classRoom = classRoom;
    }
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", classRoom=" + classRoom +
                '}';
    }
}

定义一个 StudentMapper 接口:

package com.cn.mapper;
import java.util.List;
import com.cn.pojo.Student;
public interface StudentMapper {
    List<Student> selectAllStudent();
}

编写 StudentMapper.xml

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cn.mapper.StudentMapper">
    <select id="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>
    <resultMap id="StudentAndClassRoom" type="com.cn.pojo.Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <association property="classRoom" javaType="com.cn.pojo.ClassRoom">
            <result property="id" column="cid"/>
            <result property="classname" column="cname"/>
        </association>
    </resultMap>
</mapper>

上面的这种 sql 编写模式称为结果嵌套查询,首先通过一段 sql 查询语句将需要的信息查询出来,接着通过 resultMap 对结果进行拼接。这里使用 association 将 classRoom 的信息拼接到了 classRoom 类中,实现多对一查询。

别忘了在配置类里把 mapper 映射加上,编写测试类:

public class StudentMapperTest {
    public static void main(String[] args) {
        // 获取SqlSession
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> students = mapper.selectAllStudent();
        System.out.println(students);
    }
}

一对多查询(collection)

一个教室里有多个学生,如果想要查询每个教室中的所有学生,就会用到一对多查询。

修改两个实体类,命名为 Student2 和 ClassRoom2,因为一个教室中有多个学生,因此在教室类中通过 List<Student2> 的方式引入 Student2 类

public class Student2 {
    private int id;
    private String name;
    private int classId;
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", classId=" + classId +
                '}';
    }
}

import java.util.List;
public class ClassRoom2 {
    private int id;
    private String classname;
    private List<Student2> students;
    @Override
    public String toString() {
        return "ClassRoom{" +
                "id=" + id +
                ", classname='" + classname + '\'' +
                ", students=" + students +
                '}';
    }
}

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

import java.util.List;
import com.cn.pojo.ClassRoom2;
public interface ClassRoomMapper {
    List<ClassRoom2> getClassRoomByid( int id);
}

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cn.mapper.ClassRoomMapper">
    <select id="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>
    <resultMap id="ClassRoomAndStudent" type="com.cn.pojo.ClassRoom2">
        <result property="id" column="cid"/>
        <result property="classname" column="cname"/>
        <!--对于集合属性,需要使用collection来实现-->
        <collection property="students" ofType="com.cn.pojo.Student2">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="classId" column="classid"/>
        </collection>
    </resultMap>
</mapper>

依旧是通过结果嵌套查询的方式,通过 sql 语句查询出结果,再通过 resultMap 进行组装,一对多查询用的是 collection。

在配置文件中增加 mapper 映射器之后,编写一个测试类:

public class TeacherMapperTest {
    public static void main(String[] args) {
        // 获取SqlSession
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        ClassRoomMapper mapper = sqlSession.getMapper(ClassRoomMapper.class);
        List<ClassRoom2> classRoom = mapper.getClassRoomByid(1);
        System.out.println(classRoom);
    }
}

总结成一点:对象的关联(多对一)使用 association,集合的关联(一对多)使用 collection。

懒加载

在上面的两个例子中,一次 sql 查询就将两个表的数据一次性查询了出来,这种方式就是即时加载。但是在某些业务场景下,可能只需要学生的信息或者教室的信息,而不需要两者的联表数据,这种时候就可以使用懒加载。

以上边的 association 案例解释懒加载的实现。

上边的例子中,通过联表查询一次性就查询出了学生信息和教室信息:

select s.id sid,s.name sname,c.id cid,c.classname cname
from student s,classroom c
where s.classid=c.id

如果想要通过懒加载实现,就需要把 sql 语句转换为:

select * from student;
select * from classroom where id = #{classid}

按照这个思路,建立 StudentLazyMapper 类:

package com.cn.mapper;
import java.util.List;
import com.cn.pojo.Student;
public interface StudentLazyMapper {
    List<Student> selectAllStudent();
}

创建对应的 StudentLazyMapper.xml 文件,将原先的一条 sql 转换为两条 sql:

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cn.mapper.StudentLazyMapper">
    <select id="selectAllStudent" resultMap="studentAndClassRoom">
        select * from student
    </select>
    <resultMap id="studentAndClassRoom" type="com.cn.pojo.Student">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <association property="classRoom" javaType="com.cn.pojo.ClassRoom" column="classid" select="selectClassRoomById">
            <result property="id" column="id"/>
            <result property="classname" column="classname"/>
        </association>
    </resultMap>
    <select id="selectClassRoomById" resultType="com.cn.pojo.ClassRoom">
        select * from classroom where id = #{classid}
    </select>
</mapper>

在 mybatis-config.xml 中增加 mapper 映射,为了更好地看到懒加载效果,开启控制台日志输出,完整 xml 如下:

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value=""/>
            </dataSource>
        </environment>
    </environments>
    <!--每个mapper.xml都需要在mybatis配置文件中进行配置-->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
        <mapper resource="mapper/StudentMapper.xml"/>
        <mapper resource="mapper/StudentLazyMapper.xml"/>
    </mappers>
</configuration>

新建一个测试类 StudentMapperLazyTest:

public class StudentMapperLazyTest {
    public static void main(String[] args) {
        // 获取SqlSession
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    StudentLazyMapper mapper = sqlSession.getMapper(StudentLazyMapper.class);
    List<Student> students = mapper.selectAllStudent();
    System.out.println(students.get(0).getId());
    }
}

这个时候是还没开启懒加载的,从运行结果可以看出,虽然代码中只需要得到 student 的 id,但是却查询了两张表:

在配置文件的 setting 节点下开启懒加载的配置:

<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>

再次运行测试代码:

可以看到,只有 student 一张表被查询,实现了懒加载

到此这篇关于MyBatis复杂Sql查询实现示例介绍的文章就介绍到这了,更多相关MyBatis Sql查询内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

原文出处:https://blog.csdn.net/weixin_64061088/article/details/128449

[!--infotagslink--]

相关文章

  • C#连接SQL数据库和查询数据功能的操作技巧

    本文给大家分享C#连接SQL数据库和查询数据功能的操作技巧,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友参考下吧...2021-05-17
  • Mybatis Plus select 实现只查询部分字段

    这篇文章主要介绍了Mybatis Plus select 实现只查询部分字段的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-01
  • MySQL性能监控软件Nagios的安装及配置教程

    这篇文章主要介绍了MySQL性能监控软件Nagios的安装及配置教程,这里以CentOS操作系统为环境进行演示,需要的朋友可以参考下...2015-12-14
  • PostgreSQL判断字符串是否包含目标字符串的多种方法

    这篇文章主要介绍了PostgreSQL判断字符串是否包含目标字符串的多种方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-23
  • 解决Mybatis 大数据量的批量insert问题

    这篇文章主要介绍了解决Mybatis 大数据量的批量insert问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-09
  • mybatis的Configuration详解

    这篇文章主要介绍了mybatis的Configuration详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-04
  • PostgreSQL TIMESTAMP类型 时间戳操作

    这篇文章主要介绍了PostgreSQL TIMESTAMP类型 时间戳操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-12-26
  • 详解Mysql中的JSON系列操作函数

    新版 Mysql 中加入了对 JSON Document 的支持,可以创建 JSON 类型的字段,并有一套函数支持对JSON的查询、修改等操作,下面就实际体验一下...2016-08-23
  • mybatis 返回Integer,Double,String等类型的数据操作

    这篇文章主要介绍了mybatis 返回Integer,Double,String等类型的数据操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-11-25
  • postgresql 实现多表关联删除

    这篇文章主要介绍了postgresql 实现多表关联删除操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-02
  • Postgresql 如何选择正确的关闭模式

    这篇文章主要介绍了Postgresl 如何选择正确的关闭模式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-18
  • MyBatisPlus-QueryWrapper多条件查询及修改方式

    这篇文章主要介绍了MyBatisPlus-QueryWrapper多条件查询及修改方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2022-06-27
  • 深入研究mysql中的varchar和limit(容易被忽略的知识)

    为什么标题要起这个名字呢?commen sence指的是那些大家都应该知道的事情,但往往大家又会会略这些东西,或者对这些东西一知半解,今天我总结下自己在mysql中遇到的一些commen sense类型的问题。 ...2015-03-15
  • postgresql数据添加两个字段联合唯一的操作

    这篇文章主要介绍了postgresql数据添加两个字段联合唯一的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-04
  • Oracle使用like查询时对下划线的处理方法

    这篇文章主要介绍了Oracle使用like查询时对下划线的处理方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-16
  • MySQL 字符串拆分操作(含分隔符的字符串截取)

    这篇文章主要介绍了MySQL 字符串拆分操作(含分隔符的字符串截取),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-22
  • 解决mybatis-plus 查询耗时慢的问题

    这篇文章主要介绍了解决mybatis-plus 查询耗时慢的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-07-04
  • mysql的3种分表方案

    一、先说一下为什么要分表:当一张的数据达到几百万时,你查询一次所花的时间会变多,如果有联合查询的话,有可能会死在那儿了。分表的目的就在于此,减小数据库的负担,缩短查询时间。根据个人经验,mysql执行一个sql的过程如下:1...2014-05-31
  • Vscode上使用SQL的方法

    这篇文章主要介绍了Vscode上使用SQL的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-26
  • Windows服务器MySQL中文乱码的解决方法

    我们自己鼓捣mysql时,总免不了会遇到这个问题:插入中文字符出现乱码,虽然这是运维先给配好的环境,但是在自己机子上玩的时候咧,总得知道个一二吧,不然以后如何优雅的吹牛B。...2015-03-15