MyBatis 详解

目录

1.MyBatis 框架的搭建

1.1 创建数据库和表

1.2 添加 MyBatis 依赖

1.3 设置 MyBatis 配置

1.3.1 设置数据库的连接信息

1.3.2 设置 XML 保存路径和命名格式

1.4 根据 MyBatis 写法完成数据库得操作

1.4.1 定义接口

1.4.2  使用 XML 实现接口

2.MyBatis查询操作

2.1 单表查询

2.1.1 参数占位符 #{ } 和 ${ }(常见面试问题)

从上边的事例可以看出 ${ } 可以实现的功能 #{ } 都能实现,并且 ${ } 还有 SQL 注入的问题,那么为什么 ${ } 的写法还存在?

2.1.2 ${ } 的优点

2.2 类中的属性和数据库表中的字段名不一致时,那么查询结果为 null,解决方案

2.2.1 将类中的属性和表中的字段名保持一致(最简单的解决方案)

2.2.2 使用 sql 语句中的 as 进行列名(字段名)重命名,让列名(字段名)等于属性名

2.2.3 返回字典映射:resultMap

2.3 like 查询操作

2.3.1 解决方案一:去掉单引号

2.3.2 解决方案二:mysql 内置函数 concat

3. 增、删、改操作

3.1 删除操作 + @Transactional 注解

3.2 修改用户操作

3.3 添加用户操作

3.3.1 MyBatis 添加操作,返回受影响的行数

3.3.2 返回自增 ID

4. 多表查询

4.1 一对一映射:使用注解

4.2 一对多映射:文章案例

5.动态 SQL

5.1 if 标签

5.2 trim 标签

5.3 where 标签

5.4 set 标签

5.5 foreach 标签


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

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

MyBatis 详解_第1张图片

MyBatis 学习只分为两部分:

  • 配置 MyBatis 开发环境
  • 使用 MyBatis 模式和语法操作数据库

1.MyBatis 框架的搭建

1.1 创建数据库和表

-- 创建数据库
drop database if exists mycnblog2023;
create database mycnblog2023 DEFAULT CHARACTER SET utf8mb4;

-- 使用数据数据
use mycnblog2023;

-- 创建表[用户表]
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 timestamp default current_timestamp,
    updatetime timestamp default current_timestamp,
    `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 timestamp default current_timestamp,
    updatetime timestamp default current_timestamp,
    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 timestamp default current_timestamp,
		updatetime timestamp default current_timestamp,
  	uid int
)default charset 'utf8mb4';

-- 添加一个用户信息
INSERT INTO `mycnblog2023`.`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);

1.2 添加 MyBatis 依赖

MyBatis 详解_第2张图片

新创建的 Mybatis 启动时报错是正常的,因为未设置要连接的具体 MySQL 的详细信息

1.3 设置 MyBatis 配置

1.3.1 设置数据库的连接信息

application.properties:

#设置数据库的相关连接信息
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mycnblog2023?characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

1.3.2 设置 XML 保存路径和命名格式

MyBatis 的 XML 中保存是查询数据库的具体操作 SQL:

# 设置 MyBatis XML 存放路径和命名格式
mybatis.mapper-locations=classpath:mybatis/*Mapper.xml

1.4 根据 MyBatis 写法完成数据库得操作

常规的写法,包含了两个文件:

  1. 接口:方法的声明(给其他层(service)调用)
  2. XML:实现接口

添加实体类:

package com.example.demo.model;
import lombok.Data;
import java.time.LocalDateTime;
//添加实体类
@Data
public class Userinfo {
    private int id;
    private String username;
    private String password;
    private String photo;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private int state;
}

1.4.1 定义接口

使用 @Mapper 注解,即数据持久层标志,相当于五大类注解中的 @Repository

package com.example.demo.dao;
import com.example.demo.model.Userinfo;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper //数据持久层的标志
public interface UserMapper {
    List getAll();
}

1.4.2  使用 XML 实现接口

MyBatis 固定的 xml 格式:





注意namespace 是表明当前 xml 实现的是哪个接口的(不是使用 xml 文件名和接口进行匹配的)

MyBatis 详解_第3张图片

UserMapper.xml 查询所有⽤户的具体实现 SQL:




    

其中:

  • 标签:需要指定 namespace 属性,表示命名空间,值为 mapper 接⼝的全限定名,包括全包名.类名
  • id:方法名是和 Interface(接⼝)中定义的方法名称⼀样的),表示对接⼝的具体实现方法
  • id 中需要实现一个返回类型 resultType:是返回的数据类型,也就是开头我们定义的实体类
  • 写具体的 SQL 时,注意没有分号

使用单元测试验证是否生效:在需要生成单元测试类(UserMapper)中右键 generate,生成一个 Test

package com.example.demo.dao;
import com.example.demo.model.Userinfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest //告诉当前的测试程序,目前项目时运行在 Spring Boot容器中
class UserMapperTest {
    //Spring 容器就是 IoC 容器,实现 DI,就可以把测试类(UserMapper)注入进去,使用 @Autowired 注解
    @Autowired
    private UserMapper userMapper;

    @Test
    void getAll() {
        List list = userMapper.getAll();
        System.out.println(list);
    }
}

其中:

  • 需要添加一个 @SpringBootTest 注解:告诉当前的测试程序,目前项目时运行在 Spring Boot 容器中
  • Spring 容器就是 IoC 容器,实现 DI,就可以把测试类(UserMapper)注入进去,使用 @Autowired 注解

mysql 中:

MyBatis 详解_第4张图片

运行测试类,实现功能:

MyBatis 详解_第5张图片


在这里,我介绍一种 MyBatis 插件:为了方便开发 MyBatis 实现 XML 和对应的接口之技安的快速跳转,可以安装一个 MyBatisX 插件

MyBatis 详解_第6张图片

实现快速跳转: 

MyBatis 详解_第7张图片

2.MyBatis查询操作

2.1 单表查询

根据 id 查询一条信息

 UserMapper 类:

@Mapper //数据持久层的标志
public interface UserMapper {
    //传递单个参数
    Userinfo getUserById(@Param("id") Integer id);
}
  • 传递参数需要使用包装类,不能使用基础类型(包装类可以接收 null,前端没有传递值不会报错;而基础类型会报错——500)
  • 传递非定义业务对象需要使用注解 @Param :给参数命名,比如在 mapper 里面某方法A(int id),当添加注解后A(@Param(“userId”) int id),也就是说外部想要取出传入的 id 值,只需要取它的参数名 userId 就可以了。

xml:




    

测试类:

@SpringBootTest //告诉当前的测试程序,目前项目时运行在 Spring Boot容器中
class UserMapperTest {
    @Test
    void getUserById() {
        Userinfo userinfo =  userMapper.getUserById(1);
        System.out.println(userinfo.toString());
    }
}

MyBatis 详解_第8张图片

传参有两种方式:1️⃣使用 ${ 参数名 }(使用 @value 注解读取配置文件的写法)

MyBatis 详解_第9张图片

执行语句:

2️⃣使用 #{ 参数名 }




    

MyBatis 详解_第10张图片

  • 使用 jdbc 设置的 ?,? 是一个占位符,意味着 SQL 执行的时候将是预编译处理

2.1.1 参数占位符 #{ } 和 ${ }(常见面试问题)

  1. #{ }:预编译处理
  2. ${ }:字符直接替换
  • 预编译处理:MyBatis 在处理 #{} 时,会将 SQL 中的 #{} 替换为 ? 号,使用 PreparedStatement 的 set 方法来赋值
  • 直接替换:是MyBatis 在处理 ${} 时,就是把 ${} 替换成变量的值

预编译和直接替换区别:

  • 预编译:执行是安全的,可以防止 SQL 注入
  • 直接替换:执行是不安全的

SQL 注入:使用特殊的 SQL 语句完成非法操作

例如,进行用户名和密码的判断:

假设这是一个登陆的功能 ,必须要求用户名和密码都输入正确,才能返回一条 SQL 语句;

则 SQL  注入指的是密码输入错误也能查到数据

UserMapper 类:

@Mapper //数据持久层的标志
public interface UserMapper {
    //登陆功能
    Userinfo login(@Param("username") String username, @Param("password") String password);
}

xml(使用 ${ }):




    

测试类:

@SpringBootTest //告诉当前的测试程序,目前项目时运行在 Spring Boot容器中
class UserMapperTest {
    @Test
    void login() {
        String username = "admin";
        String password = "' or 1='1";
        Userinfo userinfo = userMapper.login(username, password);
        System.out.println(userinfo.toString());
    }
}

在这里还有一个区别:

  • #{ } :使用在非数值类型或数值类型下是完全可以的
  • ${ }:非数值类型需要加 '    ' ,否则会报错

运行测试:

MyBatis 详解_第11张图片

我们发现竟然可以查询出数据:输入不是正确密码,竟然能查询处结果(这就是最简单的 SQL 注入);则 使用 ${ } ,那么可以通过 ' or 1='1 这个命令登陆各种系统—— SQL 注入

MyBatis 详解_第12张图片

使用 #{ }:




    

MyBatis 详解_第13张图片

MyBatis 在处理 #{ } 时,会将 SQL 中的 #{ } 替换为 ? 号,使用 PreparedStatement 的 set 方法来赋值


从上边的事例可以看出 ${ } 可以实现的功能 #{ } 都能实现,并且 ${ } 还有 SQL 注入的问题,那么为什么 ${ } 的写法还存在?

2.1.2 ${ } 的优点

MyBatis 详解_第14张图片

例如,SQL 语句:

select * from userinfo order by id asc;
select * from userinfo order by id desc;
  • 在这种情况下,使用 ${ } 直接替换就行
  • 使用 #{ },asc、desc 就是一个占位符,并且它是一个 String,# 就会加单引号,即 'desc'、'asc',这是不可取的

MyBatis 详解_第15张图片

  • ${ } 适用场景:当业务需要传递 SQL 命令,只能使用 ${ },不能使用 #{ }
  • ${ } 注意事项:如果要使用 ${ },那么传递的参数一定要能被穷举,否则不能使用(上述只能是 desc 或者 asc)

2.2 类中的属性和数据库表中的字段名不一致时,那么查询结果为 null,解决方案

已知数据库:

MyBatis 详解_第16张图片

类中属性(Userinfo 类):

//添加实体类
@Data
public class Userinfo {
    private int id;
    private String name;
    private String password;
    private String photo;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private int state;
}
@Test
void getAllByOrder() {
    List list = userMapper.getAllByOrder("desc");
    System.out.println(list);
}

UserMapper 类:

List getAllByOrder(@Param("myOrder") String myOrder);

XML 配置:

MyBatis 详解_第17张图片

2.2.1 将类中的属性和表中的字段名保持一致(最简单的解决方案)

MyBatis 详解_第18张图片

存在的问题: 定义的 name 已经在多个类中使用,那么把定义的 name 改为 username,随之其他类也需要改动,工作量有可能会增大

2.2.2 使用 sql 语句中的 as 进行列名(字段名)重命名,让列名(字段名)等于属性名

xml 配置修改 sql 语句:

MyBatis 详解_第19张图片

2.2.3 返回字典映射:resultMap

  • 字段名和程序中的属性名不同的情况,可使用 resultMap 配置映射
  • 一对一和一对多关系可以使用 resultMap 映射并查询数据

定义一个 resultMap,将属性名和字段名进行手动映射

UserMap.xml:


    
    
    
    
    
    

MyBatis 详解_第20张图片

id 设置到查询结果中:

MyBatis 详解_第21张图片

2.3 like 查询操作

UserMapper 类:

//like 查询
List getLikeList(@Param("username") String username);

UserMapper.xml:


生成单元测试:

@Test
void getLikeList() {
    String username = "三";
    List list = userMapper.getLikeList(username);
    System.out.println(list);
}

  • 这个时候发现使用 like 的时候报错了,因为 #{username} 是预执行,会变成 ?,则在设置 问号 的时候会加单引号 ,相当于:select * from userinfo where username like '%'username'%';
  • 换成 ${ } 可以吗?可以,但是不能去用;因为使用 ${ }的场景:数值或者能被穷举或 过滤(风险也很大,关键东西多,过滤不彻底)

2.3.1 解决方案一:去掉单引号


String username = "%三%";

这个时候就不存在单引号中在嵌套一个单引号

MyBatis 详解_第22张图片

2.3.2 解决方案二:mysql 内置函数 concat

例如:使用 concat 进行拼接

MyBatis 详解_第23张图片

UserMapper.xml:


单元测试:

String username = "三";

MyBatis 详解_第24张图片

3. 增、删、改操作

  • 标签:插入语句
  • 标签:修改语句
  • 标签:删除语句

3.1 删除操作 + @Transactional 注解

在 interface 中定义一个方法接口:

@Mapper //数据持久层的标志
public interface UserMapper {

    //删除操作
    int delById(@Param("id") Integer id);
}

Mapper.xml 实现标签:


    delete from userinfo where id = #{id}

删除操作不需要返回类型,可以不写 resultType

MyBatis 详解_第25张图片

已知数据库:

MyBatis 详解_第26张图片

生成测试类:

@SpringBootTest //告诉当前的测试程序,目前项目时运行在 Spring Boot容器中
class UserMapperTest {
    @Transactional //事务,单元测试添加 @Transactional,执行完成之后会进行回滚操作:既能实现测试功能,同时不会污染或影响数据库
    //已经构建了数据库,不能说测试的时候删除就没了
    @Test
    void delById() {
        int id = 2;
        int result = userMapper.delById(id);
        System.out.println("受影响的行数:" + result);
    }
}

添加一个注解 @Transactional,这是一个事务注解,执行完成之后会进行回滚操作,这样既能实现测试功能,同时不会污染或影响数据库(已经构建看数据库,不能说测试的时候删除就没了)

MyBatis 详解_第27张图片

这个时候我们执行数据库操作发现这条语句依然存在:

MyBatis 详解_第28张图片

没有 注解 @Transactional

MyBatis 详解_第29张图片

  • 如果测试功能,并且不想影响数据库,那么就添加一个 @Transactional 注解(适合所有场景,不单单是删除操作)

3.2 修改用户操作

UserMapper 类:

//修改操作
int update(Userinfo userinfo);

传递对象不需要用 @Param

UserMapper.xml(修改操作也不需要返回类型,不写 resultType):


    update userinfo set username = #{username} where id = #{id}

传递对象中的#{ }:括号中直接使用对象的属性名,不需要写 userinfo.username;Mybatis 框架已经默认做了这个过程

生成单元测试:

@SpringBootTest //告诉当前的测试程序,目前项目时运行在 Spring Boot容器中
class UserMapperTest {
    @Test
    void update() {
        Userinfo userinfo = new Userinfo();
        userinfo.setId(1);
        userinfo.setUsername("超级管理员");
        int result = userMapper.update(userinfo);
        System.out.println("受影响的行数:" + result);
    }
}

MyBatis 详解_第30张图片

数据库:

MyBatis 详解_第31张图片

当然如果不想影响数据库,和删除操作一样添加 @Transactional 注解

3.3 添加用户操作

3.3.1 MyBatis 添加操作,返回受影响的行数

UserMapper 类:

//修改操作
int update(Userinfo userinfo);

UserMapper.xml:


    insert into userinfo(username, password, photo) values(#{username}, #{password}, #{photo})

同理——传递对象中的#{ }:括号中直接使用对象的属性名,不需要写 userinfo.username;Mybatis 框架已经默认做了这个过程 

生成单元测试:

//添加操作
@Test
void add() {
    Userinfo userinfo = new Userinfo();
    userinfo.setUsername("张三");
    userinfo.setPassword("123");
    userinfo.setPhoto("/image/default.png");
    int result = userMapper.add(userinfo);
    System.out.println("受影响的行数:" + result);
}

MyBatis 详解_第32张图片

数据库:

这个时候发现 id 好像不是很符合,接下来我们来设置 自增id

3.3.2 返回自增 ID

UserMapper 类:

//返回自增 ID
int insert(Userinfo userinfo);

UserMapper.xml:



    insert into userinfo(username, password, photo) values(#{username}, #{password}, #{photo})

MyBatis 详解_第33张图片

  • useGeneratedKeys:这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键默认值:false
  • keyColum:数据库自增主键字段名(列名)
  • keyProoerty:指定能够唯⼀识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值

生成单元测试:

@Test
void insert() {
    Userinfo userinfo = new Userinfo();
    userinfo.setUsername("李四");
    userinfo.setPassword("123456");
    userinfo.setPhoto(" ");
    int result = userMapper.insert(userinfo);
    System.out.println("受影响的行数:" + result + " | ID:" + userinfo.getId());
}

MyBatis 详解_第34张图片

MyBatis 详解_第35张图片

4. 多表查询

4.1 一对一映射:使用注解

添加实体类:

package com.example.demo.model;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class Articleinfo {
    private int id;
    private String title;
    private String content;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private int uid;
    private int rcount;
    private int state;
    //联表字段
    private String username;
}

注解实现(查询文章的所有信息和用户的username),在这里使用 @Select 注解写 sql 相当于 xml 中的 sql:

package com.example.demo.dao;
import com.example.demo.model.Articleinfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface ArticleMapper {

    //查询注解
    //查询文章所有信息和用户的username
    @Select("select a.*,u.username from articleinfo a left join userinfo u on a.uid=u.id")
    List getAll();
}

生成测试类:

package com.example.demo.dao;
import com.example.demo.model.Articleinfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class ArticleMapperTest {

    @Autowired
    private ArticleMapper articleMapper;
    @Test
    void getAll() {
        List list = articleMapper.getAll();
        System.out.println(list);
    }
}

MyBatis 详解_第36张图片

4.2 一对多映射:文章案例

文章案例:查询一个用户的多篇文章

把查询分成两个查询:在业务类中首先查询到用户信息,再用用户的 id 去文章表里查询文章的 list,把 list 设置到文章用户的文章列表中

面试问项目有没有使用到多线程?上边案例就是如此,启动线程池,同时查询两张表(一张用户表,一张文章表),查询完成之后拼接实现查询

查询用户多篇文章,实体类 Userinfo 中添加字段:

@Data
public class Userinfo {
    private int id;
    private String username;
    private String password;
    private String photo;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private int state;

    private List alist;
}

UserMapper 类:

@Select("select * from userinfo where id=#{id}")
Userinfo getUserById2(@Param("id") Integer id);

ArticleMapper 类:

@Select("select * from articleinfo where uid=#{uid}")
List getListByUid(@Param("uid") Integer uid);

单元测试(单线程实现):

@SpringBootTest //告诉当前的测试程序,目前项目时运行在 Spring Boot容器中
class UserMapperTest {

    //Spring 容器就是 IoC 容器,实现 DI,就可以把测试类(UserMapper)注入进去,使用 @Autowired 注解
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private ArticleMapper articleMapper;
    @Test
    void getUserList() {
        int uid = 1;

        //1.根据 uid 查询 userinfo
        Userinfo userinfo = userMapper.getUserById2(uid);
        System.out.println(userinfo);

        //2.根据 uid 查询文章列表
        List list = articleMapper.getListByUid(uid);

        //组装数据
        userinfo.setAlist(list);
        System.out.println(userinfo);
    }
}

MyBatis 详解_第37张图片

多线程:

@SpringBootTest //告诉当前的测试程序,目前项目时运行在 Spring Boot容器中
class UserMapperTest {

    @Test
    void getUserList() {
        int uid = 1;

        //定义线程池
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 100, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(100));

        final Object[] resultArray = new Object[2];
        threadPool.submit(new Runnable() {
            @Override
            public void run() {
                //1.根据 uid 查询 userinfo
                resultArray[0] = userMapper.getUserById2(uid);
            }
        });

        threadPool.submit(new Runnable() {
            @Override
            public void run() {
                //2.根据 uid 查询文章列表
                resultArray[1] = articleMapper.getListByUid(uid);
            }
        });

        //组装数据(等线程池执行完成之后)
        while (threadPool.getTaskCount() != threadPool.getCompletedTaskCount()) {

        }

        Userinfo userinfo = (Userinfo) resultArray[0];
        userinfo.setAlist((List) resultArray[1]);
        System.out.println(userinfo);

    }
}

5.动态 SQL

5.1 if 标签

语法:
          
               ....
          
  • 使用场景 :在注册用户的时候,有可能分为两种注册信息,必填字段和非必填字段,如果在添加用户的时候不确定的字段传入,这时候就需要使用动态标签 来判断


    insert into userinfo(username, password
    
        ,photo
    
    ) values(#{username},#{password}
    
        ,#{photo}
    
    )

MyBatis 详解_第38张图片

5.2 trim 标签

用来去掉不必要的信息;如果所有字段都是非必填项,就考虑使用 标签结合 标签,对多个字段都采取动态生成的方式

标签的属性:

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


    insert into userinfo
        
            
                username,
            
            
                password,
            
            
                photo,
            
        
    values
    
        
            #{username},
        
        
            #{password},
        
        
            #{photo},
        
    
  • prefix 这个操作相当于在 trim 前面加 (
  • suffix 这个操作相当于在 trim 后面加 )
  • 多个 组织的语句都以 , 结尾,在最后拼接好的字符串还会以 , 结尾,会基于 suffixOverrides 配置去掉最后⼀个 

测试类:

@Test
void add3() {
    Userinfo userinfo = new Userinfo();
    userinfo.setUsername("王五");
    userinfo.setPassword("123");
    int result = userMapper.add2(userinfo);
    System.out.println("执行结果:" + result);
}

MyBatis 详解_第39张图片

5.3 where 标签

  • 传⼊的用户对象,根据属性做 where 条件查询,用户对象中属性不为 null 的,都为查询条件
  • 标签会判断里面是否有内容,如果有会动态生成 where 的 sql 语句;如果没有,则 where 关键字不会生成
  • 去除 最前面的 and 关键字

UserMapper 接⼝中新增条件查询方法:

//where 标签
List getListByWhere(Userinfo userinfo);

UserMapper.xml 中新增条件查询 sql:

    

测试类1(什么都不传,相当于没有 where 语句):

    @Test
    void getListByWhere() {
        Userinfo userinfo = new Userinfo();
        List list = userMapper.getListByWhere(userinfo);
        System.out.println(list);
    }

测试类2(传入id,正常添加 where语句):

    @Test
    void getListByWhere() {
        Userinfo userinfo = new Userinfo();
        userinfo.setId(1);
        List list = userMapper.getListByWhere(userinfo);
        System.out.println(list);
    }

MyBatis 详解_第40张图片

测试类3(where 语句可以去掉前面的 and):

    @Test
    void getListByWhere() {
        Userinfo userinfo = new Userinfo();
        //userinfo.setId(1);
        userinfo.setUsername("王五");
        //userinfo.setPassword("123");
        List list = userMapper.getListByWhere(userinfo);
        System.out.println(list);
    }

MyBatis 详解_第41张图片

上述 where标签也可以使用 trim 标签:


            

trim 里边执行到了加 where,执行不到不加 where

5.4 set 标签

  • 根据传⼊的⽤户对象属性来更新⽤户数据,可以使⽤标签来指定动态内容
  • 标签会判断里面是否有内容,如果有会动态生成 set 的 sql 语句;如果没有,则 set 关键字不会生成
  • 去掉最后面的逗号(,)

UserMapper 接⼝中新增条件查询方法:

//set 标签
int update2(Userinfo userinfo);

UserMapper.xml 中新增条件查询 sql:

    
    
        update userinfo
        
            
                username=#{username},
            
            
                password=#{password},
            
        
        where id=#{id}
    

测试类:

    @Test
    void update2() {
        Userinfo userinfo = new Userinfo();
        userinfo.setId(3);
        userinfo.setUsername("王五");
        int result = userMapper.update2(userinfo);
        System.out.println("执行结果:" + result);
    }

MyBatis 详解_第42张图片

5.5 foreach 标签

标签有如下属性:

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

根据多个⽂章 id 来删除⽂章数据。

ArticleMapper 中新增接口方法:

int deleteByIds(List ids);

ArticleMapper.xml 中新增删除 sql:


     delete from article
     where id in
     
         #{item}
     

你可能感兴趣的:(Spring,mybatis,java,数据库,spring,boot)