前言:
大家好,我是良辰丫,今天还是我们的mybatis的学习,主要内容有两个占位符,sql注入问题,like模糊匹配,以及多表查询等,不断提升我们的编程能力,加油哈! ! !

个人主页:良辰针不戳
所属专栏:javaEE进阶篇之框架学习
励志语句:生活也许会让我们遍体鳞伤,但最终这些伤口会成为我们一辈子的财富。
期待大家三连,关注,点赞,收藏。
作者能力有限,可能也会出错,欢迎大家指正。
愿与君为伴,共探Java汪洋大海。

目录

  • 1. 参数占位符 #{} 和 ${}
  • 2. $符号处理关键字
  • 3. sql注入问题
  • 4. like模糊匹配
    • 4.1 like与%连接通过#号预处理
    • 4.2 like与%连接通过$符号处理
    • 4.3 使用sql的拼接函数concat处理like
  • 5. sql字段与java后端字段不统一
    • 5.1 使用resultMap映射
    • 5.2 通过mysql的as别名
  • 7. 多表联查

1. 参数占位符 #{} 和 ${}

  • #{}:预编译处理。
  • ${}:字符直接替换。
  • 预编译处理:MyBatis 在处理#{}时,会将 SQL 中的 #{} 替换为” />Stu getStuName(@Param(“name”) String name);

    xml配置,通过#号处理字段

    <select id="getStuName" resultType="com.example.demo.entity.Stu">select * from stu where name = #{name}</select>

    测试单元

    @Testvoid getStuName() {Stu stu = stuMapper.getStuName("李白");Assertions.assertEquals(10,stu.getId());}

    测试通过

    接下来使用$号

    <select id="getStuName" resultType="com.example.demo.entity.Stu">select * from stu where name = ${name}</select>

    这个时候就会出现问题了,字符串是直接替换没有加引号.


    我们如果想要去使用$去处理字符串也可以,我们只需要再xml里面的字段加上引号即可.

    2. $符号处理关键字

    使用$可以处理关键字,比如我们sql的升序降序关键字,因为$符号是直接替换,重要的事情要多次说,这样方便大家记忆.

    创建接口字段

    List<Stu> getStuAll(String str);

    xml配置文件

    <select id="getStuAll" resultType="com.example.demo.entity.Stu">select * from stu order by id ${str};</select>

    测试单元

    @Testvoid getStuAll() {List<Stu> list = stuMapper.getStuAll("desc");}

    如果我们传关键字的时候使用#号就会报错.


    3. sql注入问题

    • 接下来我们来模拟一个登录操作,来简单描述一下我们的注入问题
    • 我们首先需要把stu表中只留下一个数据,否则属性注入会出现问题.

    定义接口信息

    Stu login(@Param("id") Integer id,@Param("name") String name);

    xml配置

    <select id="login" resultType="com.example.demo.entity.Stu">select * from stu where id = #{id} and name = #{name}</select>
    • #是不会出现属性注入的.
    • 我们主要看$符号
      $符号在处理字符串的时候需要给它加引号,sql里面单引号和双引号都可以.

    xml信息

    <select id="login" resultType="com.example.demo.entity.Stu">select * from stu where id = ${id} and name = '${name}'</select>

    测试单元

     @Testvoid login() {int id = 5;String name = "候六";//String name = "' or 1='1";Stu stu = stuMapper.login(id,name);if(stu != null){System.out.println("登录成功");}else {System.out.println("登录失败");}}

    如果我们把name属性的key值写成下面的呢” />@Testvoid login() {int id = 5;String name = “‘ or 1=’1”;Stu stu = stuMapper.login(id,name);if(stu != null){System.out.println(“登录成功”);}else {System.out.println(“登录失败”);}}

    我们会惊奇的发现这样也能查到数据库信息.

    为什么会出现上面的问题呢” /><select id=“login” resultType=“com.example.demo.entity.Stu”>select * from stu where id = #{id} and name = #{name}<!select * from stu where id = ${id} and name = ‘${name}></select>

    测试单元

    @Testvoid login() {int id = 5;//String name = "候六";String name = "' or 1='1";Stu stu = stuMapper.login(id,name);if(stu != null){System.out.println("登录成功");}else {System.out.println("登录失败");}}

    为什么#号不会出现sql注入,因为#号是预处理,它只会把那个句子当成一个value值,不会当成sql语句

    4. like模糊匹配

    like模式匹配会出问题” />4.1 like与%连接通过#号预处理

    List<Stu> getStuSel(String str);
    <select id="getStuSel" resultType="com.example.demo.entity.Stu">select * from stu where name like '#{str}%'</select>
    @Testvoid getStuSel() {String str = "李";stuMapper.getStuSel(str);}

    我们惊奇的发现此时使用#号出错了,与%联合使用并没有真正的做到拼接作用.

    4.2 like与%连接通过$符号处理

    如果我们把#号改成$号,会测试成功嘛” />

    此时竟然测试成功.

    • 虽然$符号测试成功,但是我们在上面了解到$会有sql注入的问题,那么接下来我们就要使用sql中的拼接函数concat实现我们相应的功能.
    • 这样就能保证我们既使用#号,又可以成功查询

    4.3 使用sql的拼接函数concat处理like

    <select id="getStuSel" resultType="com.example.demo.entity.Stu"><!--select * from stu where name like '${str}%'-->select * from stu where name like concat(#{str},'%')</select>

    5. sql字段与java后端字段不统一

    如果我们java后端属性和sql的字段名字不统一的时候会出现什么问题呢” /> create table stu2(id int primary key auto_increment, username varchar(20), age int);

    注意我们这个表是username属性,但是在我们java中是name属性

    然后添加一条数据.

    insert into stu2 values(null,'张三',20);

    添加接口属性

    Stu getStuId2(@Param("id") Integer id);

    添加xml配置

    <select id="getStuId2" resultType="com.example.demo.entity.Stu">select * from stu2 where id=${id}</select>

    测试单元

    @Testvoid getStuId2() {Stu stu = stuMapper.getStuId2(1);System.out.println(stu);}

    运行单元测试代码,此时我们发现后端获取到的name属性为null.

    5.1 使用resultMap映射

    这个时候我们需要使用resultMap映射,把数据库的属性和java的属性一一映射.

    添加接口方法.

    Stu getStuId2(@Param("id") Integer id);

    映射字段.

    <resultMap id="Map" type="com.example.demo.entity.Stu"><id column="id" property="id"></id><result column="username" property="name"></result><result column="age" property="age"></result></resultMap>
    • id表示主键.
    • column表示数据库的字段名.
    • id = “Map”中的Map是标识.
    • type后面添加的是要映射的实体类.
    • property是程序中的属性名
    • result普通的字段和属性,也就resultMap里的一个标签.

    xml配置

    <select id="getStuId2" resultMap="Map">select * from stu2 where id=${id}</select>

    5.2 通过mysql的as别名

    • resultMap映射中只映射name,在单表查询中没有问题,但是在多表查询有一定的问题.
    • resultMap的方式比较复杂,有没有简单的方式呢” /><select id=“getStuId2” resultType=“com.example.demo.entity.Stu”>select id,username as name,age from stu2 where id=${id}</select>

      7. 多表联查

      接下来我们创建一个学生信息表

      create table stuInfo(stuId int not null,classInfo varchar(100),ident varchar(20));

      在entity创建一个学生信息实体类StuInfo

      package com.example.demo.entity;import lombok.Data;@Datapublic class StuInfo {private int stuId;private String classInfo;private String ident;}

      在entity包下面建一个包vo,vo里面创一个类StuInfoVO

      package com.example.demo.entity.vo;import com.example.demo.entity.StuInfo;import lombok.Data;@Datapublic class StuInfoVO extends StuInfo {//不想写基础字段,可以去继承private String username;}

      在mapper包里面创一个StuInfoMapper接口

      package com.example.demo.mapper;import com.example.demo.entity.vo.StuInfoVO;import org.apache.ibatis.annotations.Mapper;import org.apache.ibatis.annotations.Param;@Mapperpublic interface StuInfoMapper {StuInfoVO getById(@Param("id") Integer id);}

      在资源文件的mybatis中添加一个配置文件StuInfoMapper.xml

      <" />="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace是命名空间,表示实现哪个接口--><mapper namespace="com.example.demo.mapper.StuInfoMapper"><select id="getById" resultType="com.example.demo.entity.vo.StuInfoVO">select id,name,classInfo,ident from stu,stuInfo where stu.id = stuInfo.stuIdand stu.id = #{id}</select></mapper>
      insert into stuInfo values(13,'计算机2020','学生会主席');
      <?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"><!--namespace是命名空间,表示实现哪个接口--><mapper namespace="com.example.demo.mapper.StuInfoMapper"></mapper>

      整体的目录结构.

      接下来我们实现一个简单的联合查询

      创建接口字段

      StuInfoVO getById(@Param("id") Integer id);

      xml文件配置

      <select id="getById" resultType="com.example.demo.entity.vo.StuInfoVO">select id,name,classInfo,ident from stu,stuInfo where stu.id = stuInfo.stuIdand stu.id = #{id}</select>

      测试单元

      package com.example.demo.mapper;import com.example.demo.entity.vo.StuInfoVO;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import static org.junit.jupiter.api.Assertions.*;@SpringBootTestclass StuInfoMapperTest {@Autowiredprivate StuInfoMapper stuInfoMapper;@Testvoid getById() {StuInfoVO stuInfoVO = stuInfoMapper.getById(13);System.out.println(stuInfoVO);}}

      通过继承的方式后端获取不到信息.

      那么,接下来我们不使用继承

      package com.example.demo.entity.vo;import com.example.demo.entity.StuInfo;import lombok.Data;@Datapublic class StuInfoVO{//不想写基础字段,可以去继承private String username;private int stuId;private String classInfo;private String ident;}

      这样后端就能成功获取到我们的sql字段.

      在多表联查中我们可以使用数据库里面的语句.

      • left join.
      • inner join.