• MyBatis


    MyBatis 是什么

    MyBatis 是一个持久层框架,也就是对整个框架里面的数据进行持久化的,是一个 ORM 框架(对象关系映射)就是连接项目和数据库的,支持自定义 SQL,存储过程 以及 高级映射。几乎去除了所有的 JDBC 代码 和 设置参数和获取结果集的⼯作。更简单的就是,MyBatis 可以更简单的完成项目和数据库的交互。

    1. 支持自定义 SQL:就是 增删改查 都可以写,也就是说明 MyBatis 是很灵活的。

    2. 存储过程:
      a)我们之前写的 SQL,不管是多复杂的 SQL,都是一行写完,因为没有复杂的业务场景。
      b)像 for 循环,判断这些都没有。但是存储是 SQL 当中的方法,由一大堆 SQL 构成。
      c)这个组成里面,是由循环,判断,分支,变量传递的。就叫做存储过程,也就是 SQL 方法化。
      d)也就是说 SQL 方法化的过程所产生的东西,就叫做存储的过程。

    3. 高级映射:除了可以实现 数据表 和 程序里面的对象 映射之外,还可以实现 一对一的多表映射 和 一对多的映射。
      a)比如说 CSDN,每一篇作者,都有它的作者,文章和作者的关系,就是一对一的关系。
      b)对作者来说,可以发很多文章,作者和文章的关系就是一对多的关系。

    4. 我们主要通过 XML 来实现 SQL 语句,因为如果用 注解的话,会导致很难写。

    使用 MyBatis

    使用 JDBC 的话,使用起来很麻烦,很繁琐。使用 MyBatis 的话,可以直接连接,使用方法很简单。我们创建一个数据库:

    -- 创建数据库
    drop database if exists mycnblog;
    create database mycnblog DEFAULT CHARACTER SET utf8mb4;
    
    -- 使用数据数据
    use mycnblog;
    
    -- 创建表[用户表]
    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';
    
    -- 创建视频表
    drop table if exists videoinfo;
    create table videoinfo(
      	vid int primary key,
      	`title` varchar(250),
      	`url` varchar(1000),
    		createtime datetime default now(),
    		updatetime datetime default now(),
      	uid int
    )default charset 'utf8mb4';
    
    -- 添加一个用户信息
    INSERT INTO `mycnblog`.`userinfo` (`id`, `username`, `password`, `photo`, `createtime`, `updatetime`, `state`) VALUES 
    (1, 'admin', 'admin', '', '2021-12-06 17:10:48', '2021-12-06 17:10:48', 1);
    
    -- 文章添加测试数据
    insert into articleinfo(title,content,uid)
        values('Java','Java正文',1);
        
    -- 添加视频
    insert into videoinfo(vid,title,url,uid) values(1,'java title','http://www.baidu.com',1);
    

    创建 MyBatis 依赖

    在创建项目的时候,就添加 MyBatis 相关依赖:
    在这里插入图片描述
    将这两个依赖全部导入就可以了,因为 MyBatis 是操作数据库的,所以也要导入 MySQL 依赖。

    如果是之前就有的项目,那么在 pom.xml 里面通过 Edit Starters 导入就好了
    在这里插入图片描述

    配置数据库连接字符串

    在启动项目之前,一定要配置数据库,不然会报错:
    在这里插入图片描述
    在配置文件当中配置数据库信息:

    #配置数据库环境
    spring:
      datasource:
        url: jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncoding=utf8
        username: root
        password: sjp151
        driver-class-name: com.mysql.cj.jdbc.Driver
    

    然后启动项目就不会报错了。

    配置 MyBatis 保存的 xml 目录

    因为 注解方式不好用,所以我们还是用 xml ,放在 resource 目录下,然后创建 mybatis 文件夹,然后放进去,也是为了提升可读性。我们创建一个 UserMapper :
    在这里插入图片描述
    然后在 配置文件 当中指定 mapper 路径:

    #配置 mybatis xml 保存路径
    mybatis:
      mapper-locations: classpath:mybatis/**Mapper.xml
    

    MyBatis 的操作模式

    一个项目的流程如下图:
    在这里插入图片描述
    MyBatis 的操作模式,有两个部分

    1. Interface(方法定义,接口)
    2. xxx.xml

    在 Interface 当中加一个 @Mapper 注解,就表示当前的这个 mybatis 类,就 实现 了对象的映射。

    第一个查询

    根据用户 id 来查询用户信息的操作,我们之前的数据库操作,就已经在 userinfo 表中插入了一个数据:
    在这里插入图片描述
    然后在 userinfo 当中写一样的属性

    @Data
    public class UserInfo {
        private int id;
        private String name;
        private String password;
        private String photo;
        private String createtime;
        private String updatetime;
        private int state;artList;
    }
    

    一定要保证和数据库当中表的内容一模一样,不然是不能操作数据库的。

    然后在 Mapper 当中就可以写数据了,在 Mapper 当中的数据,一定要写 @Mapper 注解,起名的时候,和 Mapper 中的方法名称一样,便于可读性提升,创建 xml 的时候,配置文件必须要有下面这些配置文件,直接复制就行了:

    #mapper的 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="">
    
    </mapper>
    

    里面的 namespace 写的是包名的路径:
    在这里插入图片描述
    查询的时候,也是 select 标签,然后 id 表明的是哪个 mapper,resultType 是指返回类型,也是要有 包名和类型 。UserMapper 中代码如下:

    @Mapper
    public interface UserMapper {
        public UserInfo getUserById(@Param("id") Integer id);
    }
    

    加 @param 注解是为了表示 xml 当中,用 id 可以获取到,就是通过 $ 符和 # 来获取到。

    xml 如下:

    <select id="getUserById" resultType="com.example.mybatisdemo.model.UserInfo">
        select * from userinfo where id=${id}
    select>
    

    在 Service 当中获取服务:

    @Service
    public class UserService {
    
        @Resource
        private UserMapper userMapper;
        public UserInfo getUserById(Integer id) {
            return userMapper.getUserById(id);
        }
    }
    

    然后在 Controller 当中进行检验:

    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        @RequestMapping("/getuserbyid")
        public UserInfo getUserById(Integer id) {
            if (id == null) {
                return null;
            }
            return userService.getUserById(id);
        }
    }
    

    然后直接运行就好了,使用 id 为 1:
    在这里插入图片描述

    MyBatis 执行过程

    在这里插入图片描述
    前端的程序,通过 Ajax 访问 服务器,发过来的信息,先到 Controller 层,对参数校验之后,然后把数据发给 Service 层,Service 对传输过来的信息,判断需要调用多少个接口,以及调用接口的先后顺序。

    Mapper 是单一的,不会有太复杂的业务逻辑。如果 Mapper 中的业务过于复杂,就会导致业务耦合。也就是说 MyBatis 是基于 JDBC 实现的,所以在执行的时候,还是会生成 相应的 jdbc 代码 和 sql 语句,如下:

    在这里插入图片描述

    Spring Boot 单元测试

    什么是单元测试

    1. 单元测试是对程序中的 最小单元 进行检查和验证的过程就叫做单元测试。
    2. 开发者通过一小段代码,来检验代码的一个很小的功能是否正确,是否完善。
    3. 单元测试的好处:
      a)单元测试不需要启动 Tomcat
      b)如果中途改动了代码,在项目打包的时候会发现错误,因为打包之前,所有单元测试都必须通过,然后才能打包成功。
      c)如果不使用单元测试的话,会导致访问本地数据库,也就是会 “污染” 本地数据库。

    进行单元测试的步骤

    添加测试框架

    也就是添加依赖,不过在我们现在使用的 Spring Boot 版本当中,已经自动加了以下依赖了:
    在这里插入图片描述
    所以我们就不需要重新添加了。

    先生成单元测试的类

    只需要在需要单元测试的类当中,一键生成 test 就好了:
    在这里插入图片描述
    点击之后:
    在这里插入图片描述
    生成之后如下:
    在这里插入图片描述

    配置单元测试的类

    配置类的时候,要给类加上 @SpringBootTest 注解:
    在这里插入图片描述

    然后添加单元测试的业务代码,通过 @Resource 或者 @Autowired 注解来引入:

    @SpringBootTest
    class UserMapperTest {
    
        @Autowired
        private UserMapper userMapper;
    
        @Test
        void getUserById() {
            UserInfo userInfo = userMapper.getUserById(1);
            System.out.println(userInfo);
        }
    }
    

    然后直接点击旁边的 运行 按钮就好了:
    在这里插入图片描述
    运行结果如下:
    在这里插入图片描述
    绿色的对勾表示单元测试成功,也就是通过了单元测试。

    也可以通过断言来表示单元测试是否成功,常用的断言如下:
    在这里插入图片描述
    断言代码如下:

    @SpringBootTest
    class UserMapperTest {
    
        @Autowired
        private UserMapper userMapper;
    
        @Test
        void getUserById() {
            UserInfo userInfo = userMapper.getUserById(1);
            Assertions.assertNotNull(userInfo);
        }
    }
    

    运行结果如下,绿色表示通过:
    在这里插入图片描述

    增删改查

    查询我们之前已经讲过了,还剩 增删改。

    修改方法

    代码如下:

    @Mapper
    public interface UserMapper {
        public int update(@Param("id") Integer id, @Param("username") String username);
    }
    

    xml 的 SQL 如下:
    在这里插入图片描述
    然后继续使用 单元测试 来测试就好了:

    @SpringBootTest
    class UserMapperTest {
    
        @Autowired
        private UserMapper userMapper;
    
        @Test
        void update() {
            int result = userMapper.update(2,"wangwu");
            Assertions.assertEquals(1,result);
        }
    }
    

    测试结果如图:
    在这里插入图片描述

    事务回滚

    就是在方法上面加一个 @Transactional 注解,就表示方法执行完之后,回滚数据库,数据库原始数据如下:
    在这里插入图片描述
    测试代码:

    @SpringBootTest
    class UserMapperTest {
    
        @Autowired
        private UserMapper userMapper;
    
        @Test
        void update() {
            int result = userMapper.update(2,"zhaoliu");
            Assertions.assertEquals(1,result);
        }
    }
    

    单元测试是通过的,也就是受影响的行数时 1,结果:
    在这里插入图片描述
    数据库并没有被污染,如果不加的话,数据库就被修改(污染)了。

    删除方法

    方法如下:
    在这里插入图片描述
    xml 的 SQL:
    在这里插入图片描述

    测试代码:

    @SpringBootTest
    class UserMapperTest {
    
        @Autowired
        private UserMapper userMapper;
    
        @Test
        void delete() {
            int result = userMapper.delete(2);
            System.out.println("受影响的行数:" + result);
        }
    }
    

    运行结果如下:
    在这里插入图片描述

    添加数据

    返回受影响的行数

    先添加 “返回受影响的行数” 的添加方法:
    在这里插入图片描述
    xml 当中 SQL :
    在这里插入图片描述
    测试数据:
    在这里插入图片描述

    测试结果如下:
    在这里插入图片描述

    返回自增 id

    返回自增 id,也就是需要多设置 属性名 就好了:

    <insert id="addGetId" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
        insert into userinfo(username,password,photo) values(#{username},#{password},#{photo});
    insert>
    

    也就是返回 id,测试代码如下:
    在这里插入图片描述
    运行结果如下:
    在这里插入图片描述

    ${} 和 #{} 的区别

    #{}

    先使用 # 来完成测试,针对 Integer 类型的参数:

    <select id="getUserById" resultType="com.example.mybatisdemo.model.UserInfo">
        select * from userinfo where id=#{id}
    select>
    

    测试生成的 SQL 如下:
    在这里插入图片描述
    用 # 就是先生成一个占位符,然后再去给 占位符 设置数据。占位符就是预处理(预查询)。可以很好的提升查询效率,也会更加安全。

    根据用户名字来查询

    <select id="getUserByFullName" resultType="com.example.mybatisdemo.model.UserInfo">
        select * from userinfo where username=#{username};
    select>
    

    单元测试:
    在这里插入图片描述
    运行结果如下:
    在这里插入图片描述

    ${}

    现在用 ${} ,针对 Integer 类型的参数,测试生成的 SQL 如下:
    在这里插入图片描述
    SQL 就没有 ?了,而是直接被替换为参数。就是即时查询。

    通过用户名字来查询

    <select id="getUserByFullName" resultType="com.example.mybatisdemo.model.UserInfo">
        select * from userinfo where username=${username};
    select>
    

    换成 ${} 符号之后,来查询,结果报错:
    在这里插入图片描述
    发现 lisi 并没有被引号引起来。因为 ${} 是针对 String 类型的,因为没有 引号,所以导致 SQL 出错。

    区别

    1. #{} 是预处理,${} 是直接替换。
    2. #{} 适用于所有类型的参数匹配,${} 指适用于数值类型。
    3. #{} 性能高,并且没有安全问题。但 ${} 存在 SQL 注入的问题。
    4. 如果在 构造SQL语句 的时候,如果替换的参数,是 SQL 关键字,使用 ${} 更好,比如说排序的时候,直接用 desc,asc 这样去替换。如果是用于 字段 的话,需要获取到参数类型的信息,使用 #{} 更好。

    SQL 注入

    在我们登录的时候,要传两个参数,就是用户名和密码,只有两个都正确的时候,才能登陆成功。xml 如下:

    在这里插入图片描述

    测试代码:
    在这里插入图片描述
    运行结果如下,成功通过测试案例:
    在这里插入图片描述
    如果使用 SQL 注入的话,测试代码如下

    @Test
    void login() {
        String username = "lisi";
        String password = "' or 1='1";
        UserInfo userInfo = userMapper.login(username, password);
        log.info("用户信息" + userInfo);
    }
    

    也就是在判断的时候,是通过 or 来判断的,后面的 1=1,等式恒为真,所以会成功运行:
    在这里插入图片描述
    密码是不正确的,但是却查询出来了信息,相当于没有取款密码,但是把钱取走了。换为 #{} 就不存在安全漏洞了:
    在这里插入图片描述

    • List item

    模糊查询
    通过 like 来进行模糊查询,方法如下:

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

    xml 代码如下:
    在这里插入图片描述

    测试代码如下:

    @Test
    void getListByName() {
        String username = "a";
        List<UserInfo> list = userMapper.getListByName(username);
        log.info("用户列表:" + list);
    }
    

    成功通过测试:
    在这里插入图片描述
    但是 ${} 一定会有 sql 注入的问题,所以我们就可以通过 concat 来拼接,然后通过 #{} 来完成模糊查询:

    <select id="getListByName" resultType="com.example.mybatisdemo.model.UserInfo">
        select * from userinfo where username like concat('%',#{username},'%');
    select>
    

    查询结果如下:
    在这里插入图片描述

    resultMap 和 resultType

    resultType

    如果字段名和数据库的字段名不一致的时候,就会导致查询出来的字段为 null,我们把 userinfo 的 username 换成 name,然后查询:
    在这里插入图片描述

    运行结果为 null:
    在这里插入图片描述
    所以就可以通过 resultMap 来解决这样的问题。

    resultMap

    resultMap 有两个参数,有 id 和映射的内容 type :

    <resultMap id="BaseMap" type="com.example.mybatisdemo.model.UserInfo">resultMap>
    

    然后在参数挡住设置 id 和 result 就好,id 是主键映射,result 是普通属性映射。

    1. id 里面一定要有的字段:column,就是字段名是啥。property 就是映射的属性是什么,这两个属性是必须有的。
    2. result 也有两个字段:column 是数据库对应的数据名,property 是项目中的属性名称。

    但是这样写的话,在单表查询当中是没问题的,然后在 SQL 语句当中就可以使用 resultMap :

    <resultMap id="BaseMap" type="com.example.mybatisdemo.model.UserInfo">
        <id column="id" property="id">id>
        <result column="username" property="name">result>
    resultMap>
    

    sql 如下:

    <select id="getListByName" resultMap="BaseMap">
        select * from userinfo where username like concat('%',#{username},'%');
    select>
    

    测试结果如下,现在就可以获取到名字了:在这里插入图片描述

    多表查询

    一对一查询

    多表查询当中,mybatis 是支持 一对一 和一对多 查询的。针对文章信息,写一个实体类:

    @Data
    public class ArticleInfo {
        private int id;
        private String title;
        private String content;
        private String createtime;
        private String updatetime;
        private int uid;
        private int rcount;
        private int state;
        private UserInfo userInfo;
    }
    

    通过 UserInfo 来和 user 表进行关联。建一个接口:

    @Mapper
    public interface ArticleMapper {
    
        public ArticleInfo getArticleById (@Param("id") Integer id);
    }
    

    XML 中的 SQL 代码如下:

    <select id="getArticleById" resultType="com.example.mybatisdemo.model.ArticleInfo">
        select a.*,u.id u_id,u.username u_username,u.password u_password from articleinfo a left join userinfo u on a.uid=u.id
        where a.id=#{id}
    select>
    

    测试代码:

    @SpringBootTest
    @Slf4j
    class ArticleMapperTest {
    
        @Resource
        private ArticleMapper articleMapper;
    
        @Test
        void getArticleById() {
            ArticleInfo articleInfo = articleMapper.getArticleById(1);
            log.info("文章详情" + articleInfo);
        }
    }
    

    运行结果如下:
    在这里插入图片描述
    成功通过测试,但是 userinfo 的结果为 null:
    在这里插入图片描述
    这里的 resultType 没有查询出来,那么就通过 resultMap 来完成查询。

    通过 resultMap 来完成多表查询:

    在使用的时候,也要把其它属性映射。但是属性里面还有 userinfo 所以通过 association 来连接,association 就是用来连接表的。因为两张表的信息都要查到,所以另外一张表的 xml 当中也应该写出所有配置。

    ArticleMapper 的 xml :

    <resultMap id="BaseMap" type="com.example.mybatisdemo.model.ArticleInfo">
        <id column="id" property="id">id>
        <result column="title" property="title">result>
        <result column="content" property="content">result>
        <result column="createtime" property="createtime">result>
        <result column="updatetime" property="updatetime">result>
        <result column="uid" property="uid">result>
        <result column="rcount" property="rcount">result>
        <result column="state" property="state">result>
        
        <association property="userInfo"
              resultMap="com.example.mybatisdemo.mapper.UserMapper1.BaseMap">
        association>
    resultMap>
    

    UserMapper 的 XML :

    <resultMap id="BaseMap" type="com.example.mybatisdemo.model.UserInfo">
        <id column="id" property="id">id>
        <result column="username" property="name">result>
        <result column="password" property="password">result>
        <result column="photo" property="photo">result>
        <result column="createtime" property="createtime">result>
        <result column="updatetime" property="updatetime">result>
        <result column="state" property="state">result>
    resultMap>
    

    这里 association 里面的 resultMap 也要保证 userInfo 里面有,因为是通过这个来连接的。

    XML 中的 SQL 语句:

    <select id="getArticleById" resultMap="BaseMap">
        select a.*,u.* from articleinfo a left join userinfo u on a.uid=u.id
        where a.id=#{id}
    select>
    

    查询结果如下,现在就能查到 userInfo 的信息了:
    在这里插入图片描述
    但是如果字段一样的话,就会导致值的覆盖,也就是不同表的值是一样的,为了解决这种问题,就可以通过设置前缀来解决,设置前缀就相当于是把表的字段重命名了。通过 columnPrefix 来设置前缀:

    <association property="userInfo"
          resultMap="com.example.mybatisdemo.mapper.UserMapper.BaseMap"
          columnPrefix="u_">
    association>
    

    这样的话,就不会出现数据覆盖问题了。

    一对多查询

    查询一个作者的多篇文章,通过 List 来返回:

    @Data
    public class UserInfo {
        private Integer id;
        private String username;
        private String password;
        private String photo;
        private String createtime;
        private String updatetime;
        private int state;
        //作为文章列表
        private List<ArticleInfo> artList;
    }
    

    Mapper 代码:

    public UserInfo getUserAndArticleByUid(@Param("uid") Integer uid);
    

    XML 当中,因为要用到 ArticleInfo 表,所以也要使用多表查询,通过 collection 来设置。通过 property 来约束数据类型,和 resultMap 来指定 BaseMap,然后通过 columnPrefix 来对字段重命名:

    <resultMap id="BaseMap" type="com.example.mybatisdemo.model.UserInfo">
        <id column="id" property="id">id>
        <result column="username" property="username">result>
        <result column="password" property="password">result>
        <result column="photo" property="photo">result>
        <result column="createtime" property="createtime">result>
        <result column="updatetime" property="updatetime">result>
    
        <collection property="artList"
                    resultMap="com.example.mybatisdemo.mapper.ArticleMapper.BaseMap"
                    columnPrefix="a_">
        collection>
    resultMap>
    

    XML 当中的 SQL:

    <select id="getUserAndArticleByUid" resultMap="BaseMap">
        select u.*,a.id a_id, a.title a_title,a.content a_content,a.createtime a_createtime,
               a.updatetime a_updatetime from userinfo u left join
               articleinfo a on u.id=a.uid where u.id=#{uid}
    select>
    

    测试结果如下,信息都能查到:
    在这里插入图片描述

    动态 SQL

    动态 sql 是 MyBatis 的强⼤特性之⼀,能够完成不同条件下不同的 sql 拼接。也就是有的参数是非必须传的,所以就可以通过 动态 sql 来拼接。

    if 标签

    判断一个参数是否是有值的,如果没值,那么就会隐藏 if 中的 SQL,也就是针对一些非必传参数,如果没有参数的话,就不执行 SQL,语法如下:

    <if test="username!=null">
    	username=#{username}
    if>
    

    表达式的意思是:username 的参数是否为空。如果结果是 true,那么拼接的 sql 就会加上 username=#{username} 。比如说对于非必传参数,就可以直接用 if 来选中了:

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

    这样就完成了 sql 的拼接。然后通过测试:
    在这里插入图片描述

    测试结果如下:
    在这里插入图片描述
    当 photo 不传值的时候:

    @Test
    void add2() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("zhaoliu");
        userInfo.setPassword("123");
        int result = userMapper.add2(userInfo);
        log.info("添加用户结果:" + result);
    }
    

    测试结果如下:
    在这里插入图片描述
    这里就没有 photo 了,数据库如下:
    在这里插入图片描述

    trim 标签

    最主要的作用,去除 SQL 语句前后多余的某个字符。一共有四个属性:

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

    语法如下:

    <trim prefix="(" suffix=")" prefixOverrides="," suffixOverrides=",">
    	if< test="xxx">
    	...
    	if>
    	...
    trim>
    

    再使用一个 add 方法来添加,SQL 如下:

    <insert id="add3">
        insert into userinfo
        <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="name!=null">
                #{username},
            if>
            <if test="password!=null">
                #{password},
            if>
            <if test="photo!=null">
                #{photo}
            if>
        trim>
    insert>
    

    然后进行测试,运行结果如下:
    在这里插入图片描述
    我们的 sql 语句当中,password 后面是有 逗号 的,但是这里把 逗号 省略了。

    where 标签

    主要作用是实现查询中的 where sql 替换的,它可以实现如果没有任何的查询条件,那么它可以隐藏查询中的 where sql,但如果存在 查询条件,那么会生成 where 的 sql 查询,并且使用 where 标签可以自动去除前面的 and 字符

    通过 id 来查询,SQL 如下:

    <select id="getUserById" resultMap="BaseMap">
        select * from userinfo
        <where>
            <if test="id!=null">
                id=#{id}
            if>
        where>
    select>
    

    测试结果如下:
    在这里插入图片描述
    刚刚好查询,如果不传 id 的话:
    在这里插入图片描述
    运行结果如下,就没有生成 SQL:
    在这里插入图片描述

    set 标签

    根据传⼊的⽤户对象属性来更新⽤户数据,可以使⽤标签来指定动态内容。UserMapper 接⼝中修改⽤户⽅法:根据传⼊的⽤户 id 属性,修改其他不为 null 的属性。set 标签,其实和 where 是一样的,都是替代 SQL 中的关键字。set 是 update 操作所需要使用的关键字。也是和 if 标签 配合使用的,也可以去掉最后一个符号。语法如下:

    update table
    	<set>
    		<if test="xxx">
    			...
    		if>
    		...
    	set>
    where ...
    

    更新方法:

    public int update(UserInfo userInfo);
    

    SQL 如下:

    <update id="update">
        update userinfo
        <set>
            <if test="username!=null">
                username=#{username},
            if>
            <if test="password!=null">
                password=#{password},
            if>
            <if test="photo!=null">
                photo=#{photo}
            if>
        set>
        where id=#{id}
    update>
    

    数据库原有的数据如下:
    在这里插入图片描述
    测试代码如下:

    @Test
    void update() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setUsername("bbb");
        int result = userMapper.update(userInfo);
        log.info("update 的修改结果:" + result);
    }
    

    更新之后数据库如下:
    在这里插入图片描述
    也说明 set 会自动去除最后一个逗号。set 标签也可以用 trim 来实现。

    foreach 标签

    对集合进行遍历时可以使用该标签,foreach 标签有这些属性:

    1. collection:绑定⽅法参数中的集合,如 List,Set,Map或数组对象
    2. item:遍历时的每⼀个对象(集合中的元素)
    3. open:语句块开头的字符串(类似 trim的 prefix)
    4. close:语句块结束的字符串(类似 trim的 close)
    5. separator:每次遍历之间间隔的字符串(间隔符)

    foreach 标签是 trim 所不能替代的。主要用在数据库当中批量删除数据。先在数据库当中插入数据,数据如下:
    在这里插入图片描述
    XML 当中的 SQL 如下:

    <delete id="deleteId">
        delete from userInfo where id in 
        <foreach collection="ids" open="(" close=")" item="id" separator=",">
            #{id}
        foreach>
    delete>
    

    测试代码如下:

    @Test
    void deleteId() {
        List<Integer> list = new ArrayList<>();
        list.add(6);
        list.add(7);
        list.add(8);
        int result = userMapper.deleteId(list);
        log.info("批量删除的结果:" + result);
    }
    

    运行结果如下:
    在这里插入图片描述
    数据库当中的信息:
    在这里插入图片描述
    成功完成了删除内容。

  • 相关阅读:
    【Spring Cloud】Docker的基本操作
    用键盘传输小数据,破除解决多层远程访问或防火墙限制不能粘贴复制的问题
    vue-treeselect及el-tree点击节点获取上级节点的数据
    一个合约能存储多少数据?
    【C/C++】你知道位段吗?段位?不,是位段!
    HNUCM 您好中国
    TCP、UDP 协议的区别,各自的应用场景
    被 CSDN,伤透了心
    Hive的安装与配置——第1关:Hive的安装与配置
    微信小程序--注册时获取微信头像
  • 原文地址:https://blog.csdn.net/sjp151/article/details/126942687