2022/4/17 Mybatis SQL映射文件详解

目录

1.resultMap元素自定义结果集

        1.1 要解决的问题:属性名和字段名不一致

                1.1.1 数据库中的字段

                1.1.2  Java中的实体类设计

                 1.1.3 接口

                 1.1.4 mapper映射文件

                1.1.5 总结

2.一对多与多对一处理

        2.1 数据库设计

        2.2 多对一的处理

                2.2.1 实体类编写

                2.2.2  方式一:按查询嵌套处理

                2.2.3  方式二:按结果嵌套处理

                2.2.4  小结

        2.3 一对多的处理

                2.3.1 实体类编写

                2.3.2 方式一:按结果嵌套处理 

                 2.3.3 方式二:按查询嵌套处理 

                2.3.4 小结

​​​​​​​ 3.Mybatis注解增删改查

        3.1 查询

        3.2 增加

        3.3 修改

        3.4 删除

        3.5 小结

        3.6 关于@Param注解

        3.7 #{}与${}的区别

4.Mybatis详细的执行流程

 5.Mybatis框架的缓存

        5.1 缓存简介

        5.2 Mybatis缓存 

        5.3 一级缓存

        5.4 一级缓存失效的四种情况

        5.4 二级缓存

        5.5 使用步骤

         5.6 结论

6.缓存原理 

 7.本章总结


1.resultMap元素自定义结果集

        1.1 要解决的问题:属性名和字段名不一致

                1.1.1 数据库中的字段

                1.1.2  Java中的实体类设计

package entity;

public class Banana {
    private int bd;
    private String bn;
    private String bc;
    private Place p;
    private Btype bt;

    public Banana(int bd, String bn, String bc, Place p, Btype bt) {
        this.bd = bd;
        this.bn = bn;
        this.bc = bc;
        this.p = p;
        this.bt = bt;
    }
    //get,set,构造
}

                 1.1.3 接口

package dao;

import entity.Banana;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface BananaMapper {
    /*查询所有香蕉*/
    List<Banana>getall();
    /*双表查询*/
    List<Banana>getdoubleall();
    /*查询海南产地下的所有香蕉*/
    List<Banana>getPlace(String pname);
    /*动态Mybatissql使用案例  if where*/
    /*按编号查,按名字查,按颜色查*/
    List<Banana>getfh(@Param("bid") String bid, @Param("bname") String bname, @Param("bcolor") String bcolor);
    /*动态Mybatissql使用案例  foreach*/
    /*按多颜色in查询*/
    List<Banana>getBycolor(@Param("colors")String[] colors);
    /*动态Mybatissql使用案例  set if*/
    /*多参数修改*/
    int update(Banana b);
}

                 1.1.4 mapper映射文件

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace=绑定一个对应的Dao/mapper接口-->
<mapper namespace="dao.BananaMapper">
    <resultMap id="BananaMapall" type="entity.Banana">
        <id  column="bid" property="bd"/>
        <result column="bname" property="bn"></result>
        <result column="bcolor" property="bc"></result>
    </resultMap>
    <select id="getall" resultMap="BananaMapall">
        select * from banana
    </select>


    <resultMap id="BananaMapfh" type="entity.Banana">
        <id  column="bid" property="bd"/>
        <result column="bname" property="bn"></result>
        <result column="bcolor" property="bc"></result>
    </resultMap>
    <select id="getfh" resultMap="BananaMapfh">
        select * from banana
        <where>
            <if test="bid!=null and bid!=''">
                bid=#{bid}
            </if>
            <if test="bname!=null and bname!=''">
              and bname=#{bname}
            </if>
            <if test="bcolor!=null and bcolor!=''">
                and bcolor=#{bcolor}
            </if>
        </where>
    </select>

    <select id="getBycolor" resultMap="BananaMapfh">
        select * from banana
        where bcolor
        in
        <foreach collection="colors" item="p" open="(" separator="," close=")" >
            #{p}
        </foreach>
    </select>

    <update id="update">
        update banana
        <set>
            <if test="bn!=null and bn!=''">
                bname=#{bn}
            </if>
            <if test="bc!=null and bc!=''">
                , bcolor=#{bc}
            </if>
        </set>
        where bid=#{bd}
    </update>

    <!--如果需要使用结果集映射需要先定义对应的结果集-->
    <!--mybatis默认的按照同名进行表字段映射 双表查询必须要用resultMap-->
    <!--定义的结果集映射-->
    <resultMap id="BananaMap" type="entity.Banana">
        <!--column数据库中的字段,property实体类中的属性-->
        <!--主键列用id标识-->
        <!--property:实体类字段名  column:表字段名-->
        <!--association 用于实体类中的对象的映射-->
        <id  column="bid" property="bd"/>
        <result column="bname" property="bn"></result>
        <result column="bcolor" property="bc"></result>
        <association property="p" javaType="entity.Place">
            <id  column="pid" property="pid"/>
            <result column="pname" property="pname"></result>
        </association>
        <association property="bt" javaType="entity.Btype">
            <id column="tid" property="tid"/>
            <result column="tname" property="tname"></result>
        </association>
    </resultMap>
    <select id="getdoubleall" resultMap="BananaMap">
        select * from banana b
        inner join place p on (b.pid=p.pid)
        inner join btype bt on (b.tid=bt.tid)
    </select>

    <select id="getPlace" resultMap="BananaMap">
        select * from banana b
        inner join place p on (b.pid=p.pid)
        inner join btype bt on (b.tid=bt.tid)
        where p.pname=#{pname}
    </select>
</mapper>

                1.1.5 总结

当实体类中的字段名称与数据库中的字段名不一致,或者实体类中存在对象时需要开启resultMap,手动映射字段,不然找不到对应的字段数据为空!

偷懒小技巧:可在mybatis-config.xml核心配置文件settings标签中设置 <setting name="autoMappingBehavior" value="FULL"/>开启自动映射,当实体类存在对象时需要手动配置resultMap

 <settings>
        <!--严格区分大小写,空格-->
        <!--STDOUT_LOGGING标准的日志工厂实现-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--autoMappingBehavior开启resultMap自动装配  普通列自动映射,对象列不自动映射-->
        <setting name="autoMappingBehavior" value="FULL"/>
        <!--开启二级缓存(Mapper)-->
        <setting name="cacheEnabled" value="true"/>
    </settings>

2.一对多与多对一处理

        2.1 数据库设计

        2.2 多对一的处理

多对一的理解:

  • 多个学生对应一个老师
  • 如果对于学生这边,就是一个多对一的现象,即从学生这边关联一个老师!

                2.2.1 实体类编写

@Data //GET,SET,ToString,有参,无参构造
public class Teacher {
    private int id;
    private String name;
}
@Data
public class Student {
    private int id;
    private String name;
    //多个学生可以是同一个老师,即多对一
    private Teacher teacher;
}

                2.2.2  方式一:按查询嵌套处理

  1. 给StudentMapper接口增加方法
    //获取所有学生及对应老师的信息
    public List<Student> getStudents();
  2. 编写对应的Mapper文件
    <?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.kuang.mapper.StudentMapper">
        <!--
        需求:获取所有学生及对应老师的信息
        思路:
            1. 获取所有学生的信息
            2. 根据获取的学生信息的老师ID->获取该老师的信息
            3. 思考问题,这样学生的结果集中应该包含老师,该如何处理呢,数据库中我们一般
    使用关联查询?
                1. 做一个结果集映射:StudentTeacher
                2. StudentTeacher结果集的类型为 Student
                3. 学生中老师的属性为teacher,对应数据库中为tid。
                   多个 [1,...)学生关联一个老师=> 一对一,一对多
                4. 查看官网找到:association – 一个复杂类型的关联;使用它来处理关联查
    询
        -->
        <select id="getStudents" resultMap="StudentTeacher">
         select * from student
        </select>
        <resultMap id="StudentTeacher" type="Student">
            <!--association关联属性 property属性名 javaType属性类型 column在多
    的一方的表中的列名-->
            <association property="teacher"  column="tid" javaType="Teacher" 
    select="getTeacher"/>
        </resultMap>
        <!--
        这里传递过来的id,只有一个属性的时候,下面可以写任何值
        association中column多参数配置:
            column="{key=value,key=value}"
            其实就是键值对的形式,key是传给下个sql的取值名称,value是片段一中sql查询的
    字段名。
        -->
        <select id="getTeacher" resultType="teacher">
           select * from teacher where id = #{id}
        </select>
    </mapper>
  3. 编写完毕去Mybatis配置文件中,注册Mapper
  4. 注意点说明
    <resultMap id="StudentTeacher" type="Student">
        <!--association关联属性 property属性名 javaType属性类型 column在多的一方
    的表中的列名-->
        <association property="teacher"  column="{id=tid,name=tid}" 
    javaType="Teacher" select="getTeacher"/>
    </resultMap>
    <!--
    这里传递过来的id,只有一个属性的时候,下面可以写任何值
    association中column多参数配置:
        column="{key=value,key=value}"
        其实就是键值对的形式,key是传给下个sql的取值名称,value是片段一中sql查询的字段
    名。
    -->
    <select id="getTeacher" resultType="teacher">
       select * from teacher where id = #{id} and name = #{name}
    </select>
    

                2.2.3  方式二:按结果嵌套处理

  1. 接口方法编写
    public List<Student> getStudents2();
    
  2. 编写对应的mapper文件
    <!--
    按查询结果嵌套处理
    思路:
        1. 直接查询出结果,进行结果集的映射
    -->
    <select id="getStudents2" resultMap="StudentTeacher2" >
       select s.id sid, s.name sname , t.name tname
       from student s,teacher t
       where s.tid = t.id
    </select>
    <resultMap id="StudentTeacher2" type="Student">
        <id property="id" column="sid"/>
        <result property="name" column="sname"/>
        <!--关联对象property 关联对象在Student实体类中的属性-->
        <association property="teacher" javaType="Teacher">
            <result property="name" column="tname"/>
        </association>
    </resultMap>
  3. 去mybatis-config文件中注入【此处应该处理过了】
  4. 测试
    @Test
    public void testGetStudents2(){
        SqlSession session = MybatisUtils.getSession();
        StudentMapper mapper = session.getMapper(StudentMapper.class);
        List<Student> students = mapper.getStudents2();
        for (Student student : students){
            System.out.println(
                    "学生名:"+ student.getName()
                            +"\t老师:"+student.getTeacher().getName());
       }
    }
    

                2.2.4  小结

  • 按照查询进行嵌套处理就像SQL中的子查询
  • 按照结果进行嵌套处理就像SQL中的联表查询

        2.3 一对多的处理

一对多的理解:

  • 一个老师拥有多个学生
  • 如果对于老师这边,就是一个一对多的现象,即从一个老师下面拥有一群学生(集合)!

                2.3.1 实体类编写

@Data
public class Student {
    private int id;
    private String name;
    private int tid;
}
@Data 
public class Teacher {
    private int id;
    private String name;
    //一个老师多个学生
    private List<Student> students;
}

                2.3.2 方式一:按结果嵌套处理 

  1. TeacherMapper接口编写方法
    //获取指定老师,及老师下的所有学生
    public Teacher getTeacher(int id);
  2. 编写接口对应的Mapper配置文件
    <mapper namespace="com.kuang.mapper.TeacherMapper">
        <!--
        思路:
            1. 从学生表和老师表中查出学生id,学生姓名,老师姓名
            2. 对查询出来的操作做结果集映射
                1. 集合的话,使用collection!
                    JavaType和ofType都是用来指定对象类型的
                    JavaType是用来指定pojo中属性的类型
                    ofType指定的是映射到list集合属性中pojo的类型。
        -->
        <select id="getTeacher" resultMap="TeacherStudent">
           select s.id sid, s.name sname , t.name tname, t.id tid
           from student s,teacher t
           where s.tid = t.id and t.id=#{id}
        </select>
        <resultMap id="TeacherStudent" type="Teacher">
            <result  property="name" column="tname"/>
            <collection property="students" ofType="Student">
                <result property="id" column="sid" />
                <result property="name" column="sname" />
                <result property="tid" column="tid" />
            </collection>
        </resultMap>
    </mapper>
  3. 将Mapper文件注册到MyBatis-config文件中
    <mappers>
        <mapper resource="mapper/TeacherMapper.xml"/>
    </mappers>
  4. 测试
    @Test
    public void testGetTeacher(){
        SqlSession session = MybatisUtils.getSession();
        TeacherMapper mapper = session.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacher(1);
        System.out.println(teacher.getName());
        System.out.println(teacher.getStudents());
    }
    

                 2.3.3 方式二:按查询嵌套处理 

  1. TeacherMapper接口编写方法
    public Teacher getTeacher2(int id);
  2. 编写接口对应的Mapper配置文件
    <select id="getTeacher2" resultMap="TeacherStudent2">
     select * from teacher where id = #{id}
    </select>
    <resultMap id="TeacherStudent2" type="Teacher">
        <!--column是一对多的外键 , 写的是一的主键的列名-->
        <collection property="students" javaType="ArrayList" 
    ofType="Student" column="id" select="getStudentByTeacherId"/>
    </resultMap>
    <select id="getStudentByTeacherId" resultType="Student">
       select * from student where tid = #{id}
    </select>
  3. 将Mapper文件注册到MyBatis-config文件中
  4. 测试
    @Test
    public void testGetTeacher2(){
        SqlSession session = MybatisUtils.getSession();
        TeacherMapper mapper = session.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacher2(1);
        System.out.println(teacher.getName());
        System.out.println(teacher.getStudents());
    }

                

                2.3.4 小结

  1. 关联-association
  2. 集合-collection
  3. 所以association是用于一对一和多对一,而collection是用于一对多的关系
  4. JavaType和ofType都是用来指定对象类型的
    1. JavaType是用来指定pojo中属性的类型
    2. ofType指定的是映射到list集合属性中pojo的类型。

注意说明:

  1. 保证SQL的可读性,尽量通俗易懂
  2. 根据实际要求,尽量编写性能更高的SQL语句
  3. 注意属性名和字段不一致的问题
  4. 注意一对多和多对一 中:字段和属性对应的问题
  5. 尽量使用Log4j,通过日志来查看自己的错误

​​​​​​​ 3.Mybatis注解增删改查

        3.1 查询

//根据id查询用户
@Select("select * from user where id = #{id}")
User selectUserById(@Param("id") int id);

        3.2 增加

//添加一个用户
@Insert("insert into user (id,name,pwd) values (#{id},#{name},#{pwd})")
int addUser(User user);

        3.3 修改

//修改一个用户
@Update("update user set name=#{name},pwd=#{pwd} where id = #{id}")
int updateUser(User user);

        3.4 删除

//根据id删除用户
@Delete("delete from user where id = #{id}")
int deleteUser(@Param("id")int id);

【注意点:增删改一定记得对事务的处理】 

        3.5 小结

对于简单的sql语句推荐使用注解,更加方便快捷,如果是比较复杂的sql语句推荐使用映射文件。

        3.6 关于@Param注解

@Param注解用于给方法参数起一个名字。以下是总结的使用原则:

  1. 在方法只接受一个参数的情况下,可以不使用@Param。
  2. 在方法接受多个参数的情况下,建议一定要使用@Param注解给参数命名。
  3. 如果参数是 JavaBean , 则不能使用@Param。
  4. 不使用@Param注解时,参数只能有一个,并且是Javabean。

        3.7 #{}与${}的区别

  • #{} 的作用主要是替换预编译语句(PrepareStatement)中的占位符? 【推荐使用】
INSERT INTO user (name) VALUES (#{name});
INSERT INTO user (name) VALUES (?);
  • ${} 的作用是直接进行字符串替换
INSERT INTO user (name) VALUES ('${name}');
INSERT INTO user (name) VALUES ('fangge');

4.Mybatis详细的执行流程

 5.Mybatis框架的缓存

        5.1 缓存简介

  1. 什么是缓存 [ Cache ]?
    1. 存在内存中的临时数据。
    2. 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
  2. 为什么使用缓存?
    1. 减少和数据库的交互次数,减少系统开销,提高系统效率。
  3. 什么样的数据能使用缓存?
    1. 经常查询并且不经常改变的数据 

        5.2 Mybatis缓存 

  • MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。
  • MyBatis系统中默认定义了两级缓存:一级缓存二级缓存
    • 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
    • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
    • 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

        5.3 一级缓存

一级缓存也叫本地缓存:

  • 与数据库同一次会话期间查询到的数据会放在本地缓存中。
  • 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;

        5.4 一级缓存失效的四种情况

  • 一级缓存是SqlSession级别的缓存,是一直开启的,我们关闭不了它;
  • 一级缓存失效情况:没有使用到当前的一级缓存,效果就是,还需要再向数据库中发起一次查询请求!
    1. ​​​​​​​sqlSession不同
    2. sqlSession相同,查询条件不同
    3. sqlSession相同,两次查询之间执行了增删改操作!
    4. sqlSession相同,手动清除一级缓存

        5.4 二级缓存

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
  • 工作机制
    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
    • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
    • 新的会话查询信息,就可以从二级缓存中获取内容;
    • 不同的mapper查出的数据会放在自己对应的缓存(map)中

        5.5 使用步骤

官方文档:mybatis – MyBatis 3 | XML 映射器

  1. 开启全局缓存 【mybatis-config.xml】
    <setting name="cacheEnabled" value="true"/>
    
  2. 去每个mapper.xml中配置使用二级缓存,这个配置非常简单;【xxxMapper.xml】
    <cache/>
    官方示例=====>查看官方文档
    <cache
      eviction="FIFO"
      flushInterval="60000"
      size="512"
      readOnly="true"/>
    这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 
    512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者
    产生冲突。
  3. 代码测试
    1. ​​​​​​​​​​​​​​所有的实体类先实现序列化接口
    2. 测试代码
      @Test
      public void testQueryUserById(){
          SqlSession session = MybatisUtils.getSession();
          SqlSession session2 = MybatisUtils.getSession();
          UserMapper mapper = session.getMapper(UserMapper.class);
          UserMapper mapper2 = session2.getMapper(UserMapper.class);
          User user = mapper.queryUserById(1);
          System.out.println(user);
          session.close();
          User user2 = mapper2.queryUserById(1);
          System.out.println(user2);
          System.out.println(user==user2);
          session2.close();
      }
      

       

         5.6 结论

  • 只要开启了二级缓存,我们在同一个Mapper中的查询,可以在二级缓存中拿到数据
  • 查出的数据都会被默认先放在一级缓存中
  • 只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中 

6.缓存原理 

 7.本章总结

  1. Mybatis框架的SQL映射文件提供select丶insert丶update丶delete等元素来实现SQL语句的映射。
  2. SQL映射文件的根节点是mapper元素,其namespace属性的值需要保证全局唯一,用于区分不同的mapper。
  3. 基于面向接口编程的理念,mapper元素的namespace属性值应指定为Mapper接口的完全限定类名。
  4. SQL映射文件select元素可以使用resultMap或resultType指定返回结果的类型,但是二者不能同时使用。
  5. 为Mapper接口方法传入多个简单类型的参数时,建议使用@Param注解为参数命名。
  6. resultMap元素中可以使用association元素和collection元素实现嵌套结果映射。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
MyBatis是一个开源的持久层框架,它可以将数据库操作与Java对象之间的映射关系进行配置,提供了一种简单且灵活的方式来访问数据库。 在MyBatis中,映射文件是用于定义SQL语句和结果映射的配置文件。下面是映射文件详解: 1. 命名空间(namespace):映射文件中的命名空间用于对SQL语句进行分类和管理,可以通过命名空间来引用映射文件中定义的SQL语句。 2. 结果映射(resultMap):结果映射用于将查询结果映射Java对象上。可以通过resultMap标签定义结果映射,指定查询结果与Java对象之间的对应关系。 3. SQL语句(select、insert、update、delete):映射文件中可以定义各种SQL语句,包括查询、插入、更新和删除等操作。可以通过标签(如select、insert、update、delete)来定义SQL语句,并在其中编写具体的SQL语句。 4. 参数映射(parameterType):参数映射用于将Java对象作为参数传递给SQL语句。可以通过parameterType属性指定参数类型,也可以通过parameterMap标签定义参数映射。 5. 返回值映射(resultType):返回值映射用于将查询结果转换为Java对象。可以通过resultType属性指定返回值类型,也可以通过resultMap标签引用已定义的结果映射。 6. 动态SQLMyBatis支持动态SQL,可以根据条件动态生成SQL语句。可以使用if、choose、when、otherwise等标签来实现动态SQL的编写。 7. 参数传递:映射文件中可以使用#{}或者${}来传递参数。#{}会将参数转义后传递给数据库,${}会直接将参数拼接到SQL语句中。 8. 引用其他映射文件映射文件可以通过include标签引用其他映射文件,可以将一些通用的SQL语句定义在公共的映射文件中,然后在需要的地方引用。 以上是对MyBatis映射文件详解,希望能对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Abcdzzr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值