MyBatis详解

MyBatis

1.MyBatis是什么

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

通俗点讲MyBatis就是能更简单的操作和读取数据库的工具,能更简单的完成程序和数据库的交互

mybatis – MyBatis 3 | 简介

对于后端开发来说,程序是由以下两个重要的部分组成的

  1. 后端程序
  2. 数据库

在这里插入图片描述

要实现后端程序和数据库的交互就需要数据库连接工具,数据库连接工具可以用JDBC,但是使用JDBC比较繁琐,所以可以使用MyBatis,MyBatis可以更加简单完成这项工作

接下来看一下MyBatis在整个框架的定位,框架交互:

在这里插入图片描述

MyBatis是一个ORM框架,ORM(Object Relational Mapping),即对象映射。在⾯向对象编程语⾔中,将关系型数据库中的数据与对象建⽴起映射关系,进⽽⾃动的完成数据与对象 的互相转换:

  1. 将输⼊数据(即传⼊对象)+SQL 映射成原⽣ SQL

  2. 将结果集映射为返回对象,即输出对象

  • 数据库中的表——>类
  • 记录(一行数据)——>对象
  • 字段——>对象的属性

一般的ORM框架,会将数据库模型的每张表都映射成一个类

在练习MyBatis之前,需要数据库里有几张表来练习一下

-- 使用数据数据
use practice;

-- 创建表[用户表]
drop table if exists  userinfo;
create table userinfo(
    id int primary key auto_increment,
    username varchar(100) not null,
    password varchar(32) not null,
    photo varchar(500) default '',
    createtime datetime default now(),
    updatetime datetime default now(),
    `state` int default 1
) default charset 'utf8mb4';

-- 创建文章表
drop table if exists  articleinfo;
create table articleinfo(
    id int primary key auto_increment,
    title varchar(100) not null,
    content text not null,
    createtime datetime default now(),
    updatetime datetime default now(),
    uid int not null,
    rcount int not null default 1,
    `state` int default 1
)default charset 'utf8mb4';

2. 使用MyBatis

2.1 添加MyBatis框架支持

在SpringBoot添加即可

在这里插入图片描述

2.2设置数据库和MyBatis配置

2.2.1 配置数据库的连接信息
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1/practice?characterEncoding=utf8
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
2.2.2 配置mybatis XML 文件存放位置和命名规则
mybatis:
  mapper-locations: classpath:mybatis/**Mapper.xml

在这里插入图片描述


MyBatis组成:

  1. 接口(当前类的所有方法声明)【给别人调用】
  2. xxx.xml(它和接口意义对应,一个类会有一个接口和一个对应实现操作的xml文件)存放sql

2.3使用MyBatis实现查询功能:

2.3.1 创建一个接口
@Mapper //此注解一定不能忽略
public interface UserMapper {
    public List<UserInfo> getAll();
}

2.3.2 创建与上面接口对应的xml文件(实现类中的所有的方法)

xml配置文件

<?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.example.demo.mapper.UserMapper">
    <select id="getAll" resultType="com.example.demo.model.UserInfo">
        select * from userinfo
    </select>
</mapper>
  • 标签:需要指定 namespace 属性,表示命名空间,值为 mapper 接⼝的全限定 名,包括全包名.类名。

  • 查询标签:是⽤来执⾏数据库的查询操作的: id:是和 Interface(接⼝)中定义的⽅法名称⼀样的,表示对接⼝的具体实现⽅法。 resultType:是返回的数据类型,也就是开头我们定义的实体类。

在这里插入图片描述

然后在接口那里,右键Generate->Test 搞一个单元测试,测试所写的代码是否能正确执行,单元测试代码如下:

@SpringBootTest
class UserMapperTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    void getAll() {
        List<UserInfo> list = userMapper.getAll();
        for(UserInfo user:list) {
            System.out.println(user);
        }
    }
}

运行结果:

一些注意事项看图:

在这里插入图片描述


SpringBoot单元测试方法

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述


2.4 MyBatis传参查询(使用@Param注解):

@Mapper //此注解一定不能忽略
public interface UserMapper {
    
    public UserInfo getUserById(@Param("uid") Integer id);
}

<?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.example.demo.mapper.UserMapper">
    
    <select id="getUserById" resultType="com.example.demo.model.UserInfo">
        select * from userinfo where id = #{uid}
    </select>
</mapper>

在这里插入图片描述

MyBatis ORM(对象关系)框架:实现的功能是将数据库和程序中的类进行映射,在进行映射就是使用程序中的对象的属性名和数据库中表的字段名做映射,所以默认情况下,应该将类中的属性名和表中的字段名全部一一对应上

2.4MyBatis增加功能实现(插入操作)

@Mapper
public interface ArticleInfoMapper {
    //添加方法
    public int add(@Param("articleInfo")ArticleInfo articleInfo);
}
<?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.example.demo.mapper.ArticleInfoMapper">
    <insert id="add">
        insert into articleinfo (title,content,uid)
        values(#{articleInfo.title},#{articleInfo.content},#{articleInfo.uid})
    </insert>

</mapper>

在这里插入图片描述

默认情况下返回的是受影响的⾏数

2.4.2MyBatis添家得到用户的自增id

默认情况下返回的是受影响的⾏号,如果想要返回⾃增 id,具体实现如下:

@Mapper
public interface ArticleInfoMapper {
    //添加方法
    public int add(@Param("articleInfo")ArticleInfo articleInfo);
    //添加方法(得到自增主键的id)
    public int addGetId(@Param("articleInfo")ArticleInfo articleInfo);
}
<?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.example.demo.mapper.ArticleInfoMapper">
    <insert id="add">
        insert into articleinfo (title,content,uid)
        values(#{articleInfo.title},#{articleInfo.content},#{articleInfo.uid})
    </insert>
    
    <insert id="addGetId" useGeneratedKeys="true" keyProperty="id">
        insert into articleinfo (title,content,uid)
        values(#{articleInfo.title},#{articleInfo.content},#{articleInfo.uid})
    </insert>
</mapper>

对比一下,其实就是添加了两个值useGeneratedKeys=“true” keyProperty=“id”;useGeneratedKeys表示开启自增主键, keyProperty表示将自增主键赋值给对象的属性名为id的属性

单元测试代码:

 @Test
    void addGetId() {
        ArticleInfo articleInfo = new ArticleInfo();
        articleInfo.setTitle("MyBatis添加并且返回自增id");
        articleInfo.setContent("hello MyBatis");
        articleInfo.setUid(1);
        int result = articleInfoMapper.addGetId(articleInfo);
        System.out.println("添加结果:"+result);//返回的是受影响的函数
        System.out.println("得到自增id:"+articleInfo.getId());
    }
  • useGeneratedKeys:这会令 MyBatis 使⽤ JDBC 的 getGeneratedKeys ⽅法来取出由数据库内部⽣成的主键(⽐如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的⾃动 递增字段),默认值:false。
  • keyColumn:设置⽣成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第⼀列的时候,是必须设置的。如果⽣成列不⽌⼀个,可以⽤逗号分隔多个属性 名称。
  • keyProperty:指定能够唯⼀识别对象的属性,MyBatis 会使⽤ getGeneratedKeys 的返回 值或 insert 语句的 selectKey ⼦元素设置它的值,默认值:未设置(unset)。如果⽣成列 不⽌⼀个,可以⽤逗号分隔多个属性名称。

2.5MyBatis删除功能

@Mapper
public interface ArticleInfoMapper {
    public int delById(@Param("id")Integer id);
}
<?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.example.demo.mapper.ArticleInfoMapper">
   
    <delete id="delById">
        delete from articleinfo where id = #{id}
    </delete>
</mapper>


单元测试代码:

@Test
    void delById() {
        int result = articleInfoMapper.delById(4);
        System.out.println("删除结果:"+result);
    }

2.5 MyBatis修改功能

@Mapper
public interface ArticleInfoMapper {
  
    public int updateTitle(@Param("id")Integer id,@Param("title") String title);
}
<?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.example.demo.mapper.ArticleInfoMapper">
    
    <update id="updateTitle">
        update articleinfo set title = #{title} where id = #{id}
    </update>
</mapper>


单元测试代码:

 @Test
    void updateTitle() {
        int result = articleInfoMapper.updateTitle(2,"小卢");
        System.out.println("修改结果:"+result);
    }

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

  • #{}:预编译处理。

  • ${}:字符直接替换。

预编译处理是指:MyBatis 在处理#{}时,会将 SQL 中的 #{} 替换为?号,使⽤ PreparedStatement 的 set ⽅法来赋值。直接替换:是MyBatis 在处理 ${} 时,就是把 ${} 替换成变量的值。

举个例子:把刚才修改操作的代码,将#改成$:

 <update id="updateTitle">
        update articleinfo set title = ${title} where id = #{id}
    </update>

此时程序运行就会报错

在这里插入图片描述

原因是什么呢?往下看

我们知道${}是直接替换字符,那么update articleinfo set title = KaTeX parse error: Expected 'EOF', got '#' at position 20: …le} where id = #̲{id} 这个语句中我们把{title}替换成我们要修改的值,在MySQL上跑看会不会报错

在这里插入图片描述

可以看到报错了,再看一下修改后的

在这里插入图片描述

可以看到成功了,对比两个语句是不是就是小卢和**‘小卢’**,的区别,说明在MySQL语法中要求字符串要用单引号,而KaTeX parse error: Expected 'EOF', got '#' at position 35: …报错,解决办法有两个,一个是把#̲改成符,另一个就是加上单引号

  • update articleinfo set title = #{title} where id = #{id}
  • update articleinfo set title = ‘${title}’ where id = #{id}

因为#{}会进行预编译处理,所以在检查到title是String类型时,传到数据库执行sql语句时,会加上单引号

3.2 ${} 优点

<select id="getAllBySort" parameterType="java.lang.String" resultType="com.example.demo.model.User">
 select * from userinfo order by id ${sort}
</select>

使⽤ ${sort} 可以实现排序查询,⽽使⽤ #{sort} 就不能实现排序查询了,因为当使⽤ #{sort} 查询时, 如果传递的值为 String 则会加单引号,就会导致 sql 错误。

3.3 ${}缺点(SQL注入问题)

<select id="isLogin" resultType="com.example.demo.model.UserInfo">

 select * from userinfo where username='${name}' and password='${pwd}'

</select>

假设这么个场景:你需要输入用户名和密码才能查到数据库里面用户的信息,但是如果前端给${pwd}传的参数是’ or 1='1,这样无论你用户名输入什么,都会把所有的用户信息显示出来

假设给 传的参数是小黄 , 给 {}传的参数是小黄,给 传的参数是小黄,{pwd}传的参数是’ or 1='1,那么上面的select语句变成

select * from userinfo where username = ‘小黄’ and password = ‘’ or 1=‘1’

我们把这条语句放到MySQL上跑一下:

在这里插入图片描述

可以看到我的用户名和密码都错了,但是还是能查询到,因为or 1='1’一定为真,所以查询得到

结论:⽤于查询的字段,尽量使⽤ #{} 预查询的⽅式。

4.like查询

like 使用#{} 报错

<select id="findUserByName2" resultType="com.example.demo.model.UserInfo">

select * from userinfo where username like '%#{username}%';
</select>

相当于: select * from userinfo where username like ‘%‘username’%’; 这个是不能直接使⽤ ${},可以考虑使⽤ mysql 的内置函数 concat() 来处理,实现代码如下:

<select id="findUserByName3" resultType="com.example.demo.model.User">
 select * from userinfo where username like concat('%',#{username},'%');
</select>

5.解决类中属性名和表中字段名不一致的方法:使用resultMap

resultMap 使⽤场景:

  • 字段名称和程序中的属性名不同的情况,可使⽤ resultMap 配置映射;
  • ⼀对⼀和⼀对多关系可以使⽤ resultMap 映射并查询数据
@Data
public class UserInfo {
    private int id;
    private String name;
    private String password;
    private String photo;
    private Date createtime;
    private Date updatetime;
    private int state;
}

在这里插入图片描述

可以看到数据库中一个表userinfo的字段username这个名字和UserInfo类中的name这个属性名字不一样,这样在查询,插入将会失败,此时解决办法就是resultMap

首先在xml上配置

<?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.example.demo.mapper.UserMapper">
    <resultMap id="BaseMap" type="com.example.demo.model.UserInfo">
        <id column="id" property="id"></id>
        <result column="username" property="name"></result>
    </resultMap>
    <select id="getAll" resultMap="BaseMap">
        select * from userinfo
    </select>
    <select id="getUserById" resultMap="BaseMap">
        select * from userinfo where id = #{uid}
    </select>

</mapper>

在这里插入图片描述

  • resultMap的id值是表示可以随便取

  • 是主键,如果类的属性名和数据库中的主键字段一样,不加可能不会报错,加了一定不会报错

  • 这一列表示是普通映射类,column表示数据库中的字段名,property表示类的属性名,整个表示在数据库中字段名为username映射到类中的属性名为name

6. 多表查询

一张表你最多能拿到这张表上所有字段的信息,如果你想要拿到别的表的信息,那么这时候就要进行多表查询

比如你看下面:

@Data
public class ArticleInfo {
    private int id;
    private String title;
    private String content;
    private Date createtime;
    private Date updatetime;
    private int uid;
    private int rcount;//访问量
    private int state;//状态(预览字段)
   
}
@Data
public class UserInfo {
    private int id;
    private String name;//作者名
    private String password;
    private String photo;
    private Date createtime;
    private Date updatetime;
    private int state;
}

这两个类对数据库中的两张表,但是如果你想要在articleinfo这张表中拿到userinfo表中的name信息,此时就要进行多表查询,此时怎么做呢,往下看:

首先我们想要在articleinfo拿到name,那么我们就给ArticleInfo多加个username的属性就可以了(想要拿到其他表的字段信息,就往原表所对应的类多加个属性就可了)

@Data
public class ArticleInfo {
    private int id;
    private String title;
    private String content;
    private Date createtime;
    private Date updatetime;
    private int uid;
    private int rcount;//访问量
    private int state;//状态(预览字段)
    private String username;//文章作者名(连接表需要查询的字段添加到实体类)(多表查询要拿到文章作者名,所以多加一个属性)
}

在这里插入图片描述

然后创建一个接口

@Mapper
public interface ArticleInfoMapper {
    //添加方法
   

    public List<ArticleInfo> getAll();
}

在xml上配置

<?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.example.demo.mapper.ArticleInfoMapper">
    

    <select id="getAll" resultType="com.example.demo.model.ArticleInfo">
        select a.*,u.username from articleinfo a
        left join userinfo u on a.uid=u.id
    </select>
</mapper>

单元测试代码

@Test
    void getAll() {
        List<ArticleInfo> list = articleInfoMapper.getAll();
        for(ArticleInfo item : list) {
            System.out.println(item);
        }
    }

执行结果:

在这里插入图片描述

可以看到此时就能拿到userinfo中的name信息了

所以以后如果想要拿到其他表的什么信息,只要在类中添加其他表的属性即可

还有一个问题比如说,你添加的属性和数据库中的字段名字不一样怎么办:

@Data
public class ArticleInfo {
    private int id;
    private String title;
    private String content;
    private Date createtime;
    private Date updatetime;
    private int uid;
    private int rcount;//访问量
    private int state;//状态(预览字段)
    private String name;//文章作者名(连接表需要查询的字段添加到实体类)(多表查询要拿到文章作者名,所以多加一个属性)
}

在这里插入图片描述

如图两个属性对应不上,那么在多表查询时,查出来就会为空,以上面代码,再次运行结果:

在这里插入图片描述

可以发现name为空了

这种情况有两个解决方案

  • 使用resultMap
  • 修改select语句

先来看一下使用resultMap

<?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.example.demo.mapper.ArticleInfoMapper">
    <resultMap id="BaseMap" type="com.example.demo.model.ArticleInfo">
        <id column="id" property="id"></id>
        <result column="username" property="name"></result>
    </resultMap>
    
    <select id="getAll" resultMap="BaseMap">
        select a.*,u.username from articleinfo a
        left join userinfo u on a.uid=u.id
    </select>
</mapper>


在这里插入图片描述

从运行结果可以看到这是可行的

第二种修改select语句

<select id="getAll" resultType="com.example.demo.model.ArticleInfo">
        select a.*,u.username as name from articleinfo a
        left join userinfo u on a.uid=u.id
    </select>

在这里插入图片描述

在select语句中把username命名成name也是可以看,看运行结果:
在这里插入图片描述

##7. 动态sql

动态sql是MyBatis的一个强大的特性,它能够将sql进行拼接,下面分享几个常用的标签

7.1 if标签

在某些场景中,对于表中的某个属性,填的是空还是null还是有很大区别的,就比如在我们userinfo表中,如下图

在这里插入图片描述

可以看到上面三条sql语句根据photo的不同,显现的效果也会不同,可能为空,可能是null值,可能有值

所以我们可以通过标签来根据某个条件是否成立来决定是否拼接sql语句了。

那么肯定有人问:这三条记录的photo有什么区别呢?

答:根据查询条件的不同,显示的结果也不同,比如说我想查询,photo为null的记录
在这里插入图片描述

可以发现为null值只有一条记录,而值为空的没有显示,那接下来我想查询,photo不为null的情况

在这里插入图片描述

可以发现查询出两条记录,所以这null和值为空还是有很大区别的

接下来进入正题,怎么使用if标签

(1)在UserMapper接口中声明这个方法

  //添加用户
    public int add(@Param("username") String username,@Param("password") String password,@Param("photo") String photo);

(2)在对应的xml文件中编写sql语句,if标签中还需要填写一个test属性,表示在什么条件下成立,if中的语句参与拼接.

<!--    动态sql1 if-->
    <insert id="add">
        insert into userinfo(username,
        <if test="photo!=null">
            photo,
        </if>
        password)
        values(#{username}
        <if test="photo!=null">
            ,#{photo}
        </if>
        ,#{password})
    </insert>

在这里插入图片描述

(3)接下来可以生成一个单元测试来检验一下看是否符合预期,比如我们插入一个让photo为空,也就是photo不填写任何值(包括null值)

@Test
    void add() {
        int result = userMapper.add("老七","123456",null);
        System.out.println("添加用户的结果:"+result);
    }

在这里插入图片描述

在数据库查询

在这里插入图片描述

可以看到老七就是空,不是NULL,符合我们的预期

7.2 trim标签

trim标签能够对sql语句进行前缀,后缀的添加和删除

trim标签中有如下属性:

  • prefix:表示整个语句块,以prefix的值作为前缀
  • suffix:表示整个语句块,以suffix的值作为后缀
  • prefixOverrides:表示整个语句块要去除掉的前缀
  • suffixOverrides:表示整个语句块要去除掉的后缀

之前说如果字段中有选填项用if,但如果说所有字段都是⾮必填项,就考虑使⽤ 标签结合标签,对多个字段都采取动态⽣成的⽅式。

那有人就问了,如果所有字段都是非必填项,那我干脆多用几个if标签就可了嘛,就像下面的代码一样

 <insert id="add">
        insert into userinfo(
     	<if test="username!=null">
            username,
        </if>
        <if test="photo!=null">
            photo,
        </if>
        <if test="password!=null">
            password,
        </if>
 )
        values(
     	<if test="username!=null">
            #{username},
        </if>
        <if test="photo!=null">
            #{photo},
        </if>
 		<if test="password!=null">
            #{password},
        </if>       
 )
    </insert>

但是这样会有问题,因为有些变量可能有,有些变量可能没有,你也不知道什么时候哪个变量是最后一个,那么逗号问题就处理不了,比如上述代码可能就会出现这种sql语句:

insert into userintfo (username,photo,password,) values (?,?,?,);

很显然多了两个逗号,这样在mysql执行时会报错,所以这时候就要使用trim标签配合if标签使用

(1)在接口声明方法(为了操作简便,我就直接在add方法上进行了)

//添加用户
    public int add(@Param("username") String username,@Param("password") String password,@Param("photo") String photo);

(2)在对应的xml文件编写代码

<insert id="add">
        insert into userinfo
 <!--    trim中的prefix和suffix可以对语句增加响应的前缀和后缀,比如这里的()就直接由trim帮我们添加,我们就不用在写了-->
<!--    给每一个字段后面都加上逗号,然后用suffixOverrides将作为后缀的最后一个逗号给删除掉-->
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="username!=null">
                username,
            </if>
            <if test="password!=null">
                password,
            </if>
            <if test="photo!=null">
                photo,
            </if>
        </trim>
        values
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="username!=null">
                #{username},
            </if>
            <if test="password!=null">
                #{password},
            </if>
            <if test="photo!=null">
                #{photo},
            </if>
        </trim>
    </insert>

在以上 sql 动态解析时,会将第⼀个 部分做如下处理: 基于 prefix 配置,开始部分加上 (

基于 suffix 配置,结束部分加上 )

多个 组织的语句都以 , 结尾,在最后拼接好的字符串还会以 , 结尾,会基于 suffixOverrides 配置去掉最后⼀个 ,

(3)生成单元测试

 @Test
    void add() {
        int result = userMapper.add("老八","123456",null);
        System.out.println("添加用户的结果:"+result);
    }

运行结果:

在这里插入图片描述

数据库验证:

在这里插入图片描述

符合预期

7.3 where标签

使用场景:用户想要在userinfo表中根据username进行查询,但是这个筛选条件可能为空,如果这个筛选条件为空,我们规定查询userinfo表中的所有记录

where标签作用

  • 根据标签的内容,决定要不要拼接where语句;当然如果全部不拼接,sql中的where关键字不会存在
  • 去掉where语句中最前面的and或者or关键字,让sql符合数据库的执行标椎

(1)在接口中声明方法

public List<UserInfo> getUserByName(@Param("username") String username);

(2)在对应的xml文件编写代码

<!--    作用:-->
<!--    1.根据<where>标签的内容,决定要不要拼接where语句-->
<!--    2.去掉最前面的and关键字,让sql符合数据库的执行标椎-->
    <select id="getUserByName" resultType="com.example.demo.model.UserInfo">
        select * from userinfo
        <where>
            <if test="username!=null">
                and username=#{username}
            </if>
        </where>
    </select>

(3)生成单元测试

@Test
    void getUserByName() {
        List<UserInfo> list = userMapper.getUserByName(null);
        for(UserInfo userInfo:list) {
            System.out.println("userinfo->"+userInfo);
        }

    }

运行结果:

在这里插入图片描述

7.4 set标签

根据传⼊的⽤户对象属性来更新⽤户数据,可以使⽤标签来指定动态内容。

set标签搭配update语句来使用

set标签作用

  • 生成关键字set
  • 去掉最后一个逗号

注意:使用标签至少要更新一个属性,不然会报错

场景:根据指定id修改用户名和密码

(1)在接口中声明方法

 //根据id修改用户名和密码
    public int updateById(@Param("id") Integer id,@Param("username") String username,@Param("password") String password);

(2)在xml文件中编写代码

<!--   动态sql4 set -->
<!--    作用:-->
<!--    1. 生成set关键值-->
<!--    2. 去掉最后一个','-->
    <update id="updateById">
        update userinfo
        <set>
            <if test="username != null">
                username = #{username},
            </if>
            <if test="password != null">
                password = #{password},
            </if>
        </set>
        where id = #{id}
    </update>

(3)生成单元测试(我们将id为4的用户,用户名不修改,修改密码为123)

 @Test
    void updateById() {
        int result = userMapper.updateById(4,null,"123");
    }

查询数据库验证:

在这里插入图片描述

符合预期

7.5 foreach标签

对集合进⾏遍历时可以使⽤该标签。

标签有如下属性:

  • collection:绑定⽅法参数中的集合,如 List,Set,Map或数组对象
  • item:遍历时的每⼀个对象
  • open:语句块开头的字符串
  • close:语句块结束的字符串
  • separator:每次遍历之间间隔的字符串

使用场景:在userinfo表中删除指定id的记录

正常情况下,我们想从userinfo表中删除若干个Id记录,sql语句是:delete from userinfo where id in (…),那么(…)就是我们需要遍历的集合,在MyBatis中实现就要用到标签

(1)在接口中声明方法

//多条用户的删除
    public int delByIds(@Param("ids") List<Integer> ids);

(2)在对应的xml文件编写代码

<!--    动态sql5 foreach-->
    <delete id="delByIds">
        delete from userinfo where id in
        <foreach collection="ids" item="item" open="(" close=")" separator=",">
            #{item}
        </foreach>
    </delete>
</mapper>

在这里插入图片描述

(3)生成单元测试

@Test
    void delByIds() {
        List<Integer> list = new ArrayList<>();
        list.add(7);
        list.add(6);
        int result = userMapper.delByIds(list);
        System.out.println("删除结果:"+result);
    }

运行结果:

在这里插入图片描述

数据库查询验证:
在这里插入图片描述

符合预期

全部代码

代码

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值