Bootstrap

Mybatis-Plus

一.MybatisPlus简介


1.1 MybatisPlus概述
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增
强不做改变
,为简化开发、提高效率而生(提供了快速使用mybatis的方式)。
官网:https://mybatis.plus/或者MyBatis-Plus 🚀 为简化开发而生
MP愿景是成为 MyBatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率翻
倍。

1.2 MP特性

无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可
实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无
需再担心字段写错
支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 -
Sequence),可自由配置,完美解决主键问题
支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承
Model 类即可进行强大的 CRUD 操作
支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere

内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、
Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件
之后,写分页等同于普通 List 查询
分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、
HSQL、SQLite、Postgre、SQLServer 等多种数据库
内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功
能,能快速揪出慢查询
内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义
拦截规则,预防误操作

1.3 开发MP版本

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus</artifactId>
    <version>3.4.2</version>
</dependency>

二.MP快速入门

2.1 MP入门流程分析

        SpringBoot 整合 MyBatis-Plus,并实现根据Id查询功能。
        数据库环境准备
        创建SpringBoot工程,引入MyBatisPlus场景依赖
        在yml中编写DataSource相关配置
        编写mapper
        测试

2.2 数据库环境准备

CREATE TABLE tb_user (
id bigint(20) NOT NULL AUTO_INCREMENT,
user_name varchar(255) DEFAULT NULL,
password varchar(255) DEFAULT NULL,
name varchar(255) DEFAULT NULL,
age int(11) DEFAULT NULL,
email varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO tb_user VALUES (1, '赵一伤', '123456', 'zys', 19,
'[email protected]');
INSERT INTO tb_user VALUES (2, '钱二败', '123456', 'qes', 18,
'[email protected]');
INSERT INTO tb_user VALUES (3, '孙三毁', '123456', 'ssh', 20,
'[email protected]');
INSERT INTO tb_user VALUES (4, '李四摧', '123456', 'lsc', 20,
'[email protected]');
INSERT INTO tb_user VALUES (5, '周五输', '123456', 'zws', 20,
'[email protected]');
INSERT INTO tb_user VALUES (6, '吴六破', '123456', 'wlp', 21,
'[email protected]');
INSERT INTO tb_user VALUES (7, '郑七灭', '123456', 'zqm', 22,
'[email protected]');
INSERT INTO tb_user VALUES (8, '王八衰', '123456', 'wbs', 22,
'[email protected]');
INSERT INTO tb_user VALUES (9, '张无忌', '123456', 'zwj', 25,
'[email protected]');
INSERT INTO tb_user VALUES (10, '赵敏', '123456', 'zm', 26,
'[email protected]');
INSERT INTO tb_user VALUES (11, '赵二伤', '123456', 'zes', 25,
'[email protected]');
INSERT INTO tb_user VALUES (12, '赵三伤', '123456', 'zss1', 28,
'[email protected]');
INSERT INTO tb_user VALUES (13, '赵四伤', '123456', 'zss2', 29,
'[email protected]');
INSERT INTO tb_user VALUES (14, '赵五伤', '123456', 'zws', 39,
'[email protected]');
INSERT INTO tb_user VALUES (15, '赵六伤', '123456', 'zls', 29,
'[email protected]');
INSERT INTO tb_user VALUES (16, '赵七伤', '123456', 'zqs', 39,
'[email protected]');

2.3 创建工程,引入场景依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

    <groupId>com.lzw</groupId>
    <artifactId>mp_01</artifactId>
    <version>1.0-SNAPSHOT</version>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.10.RELEASE</version>
</parent>

<dependencies>
    <!-- mysql 驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!-- lombok ,自动生成get,Set 方法-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <!--mybatisplus起步依赖-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.2</version>
    </dependency>
    </dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

</project>

2.4 在yml中编写DataSource相关配置

#datasource
spring:
    datasource:
        url: jdbc:mysql://localhost:3306/mp?
        useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
        username: root
        password: 123456
        driver-class-name: com.mysql.cj.jdbc.Drive

如果想在mybatis-plus自行是看打印的sql,可配置

#mybatis-plus配置控制台打印完整带参数SQL语句
mybatis-plus:
    configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
2.5 编写代码

实体类:

/**
* @author lzw
* @create 2024-12-14 23:31
*
* @TableName("tb_user") 实体类基于注解与表进行映射
* 如果实体类名称与表名一致,可以省略该注解
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user")
public class User {
    private Long id;
    private String userName;//默认驼峰映射
    private String password;
    private String name;
    private Integer age;
    private String email;
}

@TableName("tb_user”) : 如果数据库的表名和实体类一致时可以省略

编写mapper接口:

/**
* @author lzw
* @create 2024-12-14 23:37
*
* 使用mp定义Mapper,需要让Mapper接口继承 BaseMapper接口。
*/
public interface UserMapper extends BaseMapper<User> {
}

        启动类增加 @MapperScan 注解

@SpringBootApplication
@MapperScan("com.lzw.mapper")
public class SpringBootApp {
public static void main(String[] args) {
    SpringApplication.run(SpringBootApp.class, args);
 }
}
2.6 测试
package com.lzw.test;
import com.lzw.mapper.UserMapper;
import com.lzw.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author lzw
* @create 2024-12-14 23:40
*/
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    //根据id查询
    @Test
    public void test01(){
        User user = userMapper.selectById(1L);
        System.out.println(user);
 }
}

三.MP实现常规增删改操作


通过查看BaseMapper源码,我们发现该接口几乎定义了所有常规的增删改查操作:

3.1 MP实现插入操作

BaseMapper定义操作方法

/**
* 插入一条记录
*
* @param entity 实体对象
*/
int insert(T entity);

如果主键对应的实体类属性中没有设置主键的生成策略,那么MP自动为主键生
成值,且回填到实体对象下;


如果未指定主键生成策略,即使表的主键是主键自增,也不会使用主键自增;


插入数据时,我们发现表中ID设置默认自增,但是实际生成的id却是很长串的数
字?

//插入一条数据
@Test
public void test02(){
User user=new User();
user.setUserName("zhangsan");
user.setPassword("123456");
user.setAge(23);
user.setEmail("[email protected]");
user.setName("张三");
int row = userMapper.insert(user);
System.out.println(row);
}

3.2 MP主键字段注解-@TableId

@TableId注解作用:
        映射表中主键字段与实体类属性的关系(尤其表中主键字段名称与实体类属
        性名称不一致时);
        定义主键生成策略;
@TableId使用:
        添加在实体类的主键对应的成员属性上即可;

/**
* @author lzw
* @create 2024-12-14 23:31
*
* @TableName("tb_user") 实体类基于注解与表进行映射
* 如果实体类名称与表名一致,可以省略该注解
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user")
public class User {
/*
1.当表中列的名称与实体类中属性不一致时
2.指定主键值的生成策略,默认基于雪花算法生成
*/
    @TableId("id")
    private Long id;
    private String userName;//默认驼峰映射
    private String password;
    private String name;
    private Integer age;
    private String email;
}

3.3 MP主键生成策略

        主键生成策略:
是指为数据库生成主键的方式,我们前面学的数据库主键自增也是一种生成主键的策
略,当然除了数据库服务端帮助我们维护主键之外,客户端也可以对主键值进行生成
维护。
        MP主键生成策略示例

//指定主键自增的生成策略
@TableId(value = "user_id",type = IdType.AUTO)
private Integet userId;

MP提供的常用主键生成策略如下:

3.4 普通列注解-@TableField

注解@TableField作用:
        指定表中普通字段与实体类属性之间的映射关系;
        忽略实体类中多余属性与表中字段的映射关系(@TableField(exist = false));
以下情况可以省略:
        名称一样
        数据库字段使用_分割,实体类属性名使用驼峰名称(自动开启驼峰映射)

/**
* @author lzw
* @create 2024-12-14 23:31
*
* @TableName("tb_user") 实体类基于注解与表进行映射
* 如果实体类名称与表名一致,可以省略该注解
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user")
public class User {
/*
1.当表中列的名称与实体类中属性不一致时
2.指定主键值的生成策略,默认基于雪花算法生成
*/
@TableId(value = "id",type = IdType.AUTO)
private Long id;
//表中的列名如果与实体类属性不遵循驼峰映射或者不一致,需要通过该注解指定
    @TableField(value = "user_name")
    private String realName;
    private String password;
    private String name;
    private Integer age;
    private String email;
    @TableField(exist = false)
    private String address;
}
3.5 MP实现删除操作

BaseMaper定义的常用删除方法:

根据id删除:

//根据id删除
@Test
public void test03(){
int row = userMapper.deleteById(19L);
System.out.println(row);
}

根据id集合批量删除

//根据id集合批量删除
@Test
public void test04(){
    int row = userMapper.deleteBatchIds(Arrays.asList(17L,18L));
    System.out.println(row);
}

根据map构造条件,删除

//根据Map集合构造条件 删除
@Test
public void test05(){
Map<String,Object> map=new HashMap<>();
map.put("user_name","赵五伤");
map.put("name","zws");
int row = userMapper.deleteByMap(map);
System.out.println(row);
}
3.6 MP实现更新操作

根据实体对象中的id更新数据
注意事项:只更新实体类中存在的数据,如果对应的属性为null,不更新;

//根据ID修改数据
@Test
public void test06(){
    User user=new User();
    user.setId(1L);
    user.setPassword("111111");
    int row = userMapper.updateById(user);
    System.out.println(row);
}
3.7 MP实现分页查询

配置分页拦截器:

package com.lzw.config;
import com.baomidou.mybatisplus.annotation.DbType;
import
com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import
com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerIn
terceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author lzw
* @create 2024-12-16 22:45
*/
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

    PaginationInnerInterceptor paginationInnerInterceptor 
                = new PaginationInnerInterceptor(DbType.MYSQL);
    //设置请求的页面大于最大页后操作, true调回到首页,false 继续请求默认false
    // paginationInterceptor.setOverflow(false);
    // 设置最大单页限制数量,-1不受限制
    paginationInnerInterceptor.setMaxLimit(-1L);
    interceptor.addInnerInterceptor(paginationInnerInterceptor);
    return interceptor;
  }
}

查询测试

//不带条件分页查询
@Test
public void test07(){
int currPage=1;//当前页
int pageSize=5;//每页查多少
IPage<User> page = new Page(currPage,pageSize);
//分页相关数据会封装到IPage中
userMapper.selectPage(page,null);
//获取分页相关数据
long pages = page.getPages();//总页数
System.out.println(pages);
long total = page.getTotal();//总条数
System.out.println(total);
List<User> records = page.getRecords();//页面上显示的数据
System.out.println(records);
long current = page.getCurrent();//当前页
System.out.println(current);
long size = page.getSize();//当前页面条数
System.out.println(size);
}
3.8 QueryWrapper实现基础查询


3.8.1 QueryWrapper常用API

Wrapper接口:
QueryWrapper //查询
UpdateWrapper //更新
QueryWrapper常用API
eq(): 等于 =
ne(): 不等于 <> 或者 !=
gt(): 大于 >
ge(): 大于等于 >=
lt(): 小于 <
le(): 小于等于 <=
between(): BETWEEN 值1 AND 值2
notBetween(): NOT BETWEEN 值1 AND 值2
in(): in
notIn():not in

3.8.2 查询实现

要求:查询用户中姓名包含"伤",密码为"123456",且年龄为19或者25或者29,查询
结果按照年龄降序排序;

//查询实现
@Test
public void test08(){
/*
如果查询的条件过于复杂,mp还适合么?
简单的操作,直接使用mp
但是非常复杂的操作,比如多表关联查询 复杂条件查询等,建议使用
xml下sql实现
*/
//构建添加包装对象
QueryWrapper<User> wrapper = new QueryWrapper<>();
//设置条件
wrapper.like("user_name","伤")
.eq("password","123456")
//.in("age",19,25,29)
.in("age",Arrays.asList(19,25,29))
.orderByDesc("age");
//查询
/*
==> Preparing: SELECT
id,user_name,password,name,age,email FROM tb_user WHERE (user_name
LIKE ? AND password = ? AND age IN (?,?,?)) ORDER BY age DESC
==> Parameters: %伤%(String), 123456(String),
19(Integer), 25(Integer), 29(Integer)
*/

List<User> userList = userMapper.selectList(wrapper);
System.out.println(userList);
}

3.8.3 QueryWrapper逻辑查询or
        通过QueryWrapper多条件查询时,默认使用and关键字拼接SQL;
        通过QueryWrapper调用or()方法时,底层会使用or关键字拼接方法左右的查询条件;
        要求:查询用户名为"lisi"或者年龄大于23的用户信息;

@Test
public void test09(){
//1.创建查询条件构建器
QueryWrapper<User> wrapper = new QueryWrapper<>();
//2.设置条件
wrapper.eq("user_name","lisi")
.or()
.lt("age",23);
/*
select * from tb_user where user_name = ? or age < ?
*/
List<User> userList = userMapper.selectList(wrapper);
System.out.println(userList);
}

3.8.4 QueryWrapper模糊查询like
        like("表列名","条件值"); 作用:查询包含关键字的信息,底层会自动添加匹配关
        键字,比如:%条件值%
        likeLeft("表列名","条件值"); 作用:左侧模糊搜索,也就是查询以指定条件值结尾
        的数据,比如:%条件值
        likeRight("表列名","条件值");作用:右侧模糊搜索,也就是查询以指定条件值开
        头的数据,比如:条件值%

@Test
public void test10(){
//1.创建查询条件构建器
QueryWrapper<User> wrapper = new QueryWrapper<>();
//2.设置条件
wrapper.likeLeft("user_name","zhang");
/*
SELECT id,user_name,password,name,age,email
from tb_user
where user_name like ?
%zhang
*/
List<User> userList = userMapper.selectList(wrapper);
System.out.println(userList);
}

3.8.5 QueryWrapper排序查询
orderByAsc 升序排序,方法内可传入多个字段
orderByDesc 降序排序,方法内可传入多个字段
需求:根据age升序排序

@Test
public void test11(){
//1.创建查询条件构建器
QueryWrapper<User> wrapper = new QueryWrapper<>();
//2.设置条件
wrapper.eq("user_name","lisi")
.or()
.lt("age",23)
.in("name","李四","王五")
.orderByDesc("age");
/*
select * from tb_user where user_name = ? or age < ?
and name in (?,?) order by age asc
*/
List<User> userList = userMapper.selectList(wrapper);
System.out.println(userList);
}

3.8.6 QueryWrapper限定字段查询
        MP查询时,默认将表中所有字段数据映射查询,但是有时我们仅仅需要查询部分字
        段信息,这是可以使用select()方法限定返回的字段信息,避免I/O资源的浪费;
        示例:wrapper.select("字段1","字段2",......)

@Test
public void test12(){
//1.创建查询条件构建器
QueryWrapper<User> wrapper = new QueryWrapper<>();
//2.设置条件
wrapper.eq("user_name","lisi")
.or()
.lt("age",23)
.select("id","user_name as realName");
/*
==> Preparing: SELECT id,user_name as realName FROM
tb_user WHERE (user_name = ? OR age < ?)
==> Parameters: lisi(String), 23(Integer)
*/
List<User> userList = userMapper.selectList(wrapper);
System.out.println(userList);
}

3.8.7 QueryWrapper实现分页条件查询

方法说明:

//参数1:分页对象
//参数2:查询条件
mapper.selectPage(page,wrapper);

需求:查询年龄大于23的用户信息,并显示第2页,每页大小为3;

@Test
public void test13(){
int currPage=1;//当前页
int pageSize=5;//每页查多少
IPage<User> page = new Page(currPage,pageSize);
QueryWrapper<User> wrapper = new QueryWrapper();
wrapper.lt("age",23);
//分页相关数据会封装到IPage中
userMapper.selectPage(page,wrapper);
//获取分页相关数据
long pages = page.getPages();//总页数
System.out.println(pages);
long total = page.getTotal();//总条数
System.out.println(total);
List<User> records = page.getRecords();//页面上显示的数据
System.out.println(records);
long current = page.getCurrent();//当前页
System.out.println(current);
long size = page.getSize();//当前页面条数
System.out.println(size);
}

3.8.8 QueryWrapper实现条件删除

@Test
public void test14(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("user_name","赵四伤");
int i = userMapper.delete(wrapper);
System.out.println(i);
}

3.8.9 QueryWrapper实现条件更新

@Test
public void test14(){
// 参数1: 最新的值
    User user = new User();
    user.setRealName("张三丰");
    //参数2:更新时条件
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("id",12L);
    int update = userMapper.update(user, wrapper);
    System.out.println(update);
}

3.9 自定义查询接口实现分页查询
目前我们使用MP自带的分页插件可以很友好的实现分页查询操作,但是如果一些查
询需要我们自定义SQL,那该如何实现分页查询操作呢?
        自定义接口中直接传入Page分页对象即可;

public interface UserMapper extends BaseMapper<User> {
/**
* 查询大于指定id的用户信息,并分页查询实现
* @param page
* @param id
* @return
*/
IPage<User> findGtIdByPage(IPage<User> page, @Param("id") Longid);
}

定义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.lzw.mapper.UserMapper">
<select id="findGtIdByPage" resultType="com.lzw.pojo.User">
select * from tb_user where id > #{id}
</select>
</mapper>

测试

@Test
public void test14(){
IPage<User> page=new Page<>(2,3);
    IPage<User> users = userMapper.findGtIdByPage(page, 3l);
    System.out.println(users.getRecords());
    System.out.println(users.getPages());
    System.out.println(users.getTotal());
}

四.MP实现Service封装

4.1 MP封装Service介绍

MybatisPlus为了开发更加快捷,对业务层也进行了封装,直接提供了相关的接口和
实现类; 我们在进行业务层开发时,可以继承它提供的接口和实现类,使得编码更加
高效;
        实现流程
                *定义一个服务扩展接口,该接口继承公共接口IService;
                *定义一个服务实现类,该类继承ServiceImpl<Mapper,Entity>,并实现自定
                义的扩展接口;
        注意事项
        ServiceImpl父类已经注入了UserMapper对象,名称叫做baseMapper,所以当
        前实现类直接可以使用baseMapper完成操作。


        因为ServiceImpl已经实现了IService下的方法,所以当前服务类没有必要再次实现。


        共性的业务代码交给框架封装维护,非共性的业务,在接口UserService定义,
        然后在当前的服务类下实现;

4.2 核心API介绍

4.3 MP封装Service快速入门

定义服务扩展接口
 

//在公共接口的基础上扩展
public interface UserService extends IService<User> {
}

定义服务实现:

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
implements UserService{
}

测试:

@SpringBootTest
public class UserServiceTest {
    @Autowired
    private UserService userService;
    //根据id查询
    @Test
    public void test01(){
    User user = userService.getById(1L);
    System.out.println(user);
 }
}

4.4 MP封装Service实现CRUD操作

/**
*测试条件查询,且仅返回一个
*sql查询的结果必须为1条或者没有,否则报错 !!!!
*/
@Test
public void test02(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.gt("age",20);
User user = userService.getOne(wrapper);
System.out.println(user);
}
/**
* 根据条件批量查询
*/
@Test
public void test03(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.gt("age",20);
List<User> userList = userService.list(wrapper);
System.out.println(userList);
}
/**
*根据条件批量查询并分页
*/
@Test
public void test04(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.gt("age",20);
    //构建分页对象
    IPage<User> page=new Page<>(2,3);
    userService.page(page,wrapper);
    System.out.println(page.getRecords());
    System.out.println(page.getPages());
    System.out.println(page.getTotal());
}
/**
* 测试服务层save保存单条操作
*/
@Test
    public void test05(){
    User user=new User();
    user.setRealName("zhangsan");
    user.setPassword("123456");
    user.setAge(23);
    user.setEmail("[email protected]");
    user.setName("张三");
    boolean isSuccess = userService.save(user);
    System.out.println(isSuccess?"保存成功":"保存失败");
}
/**
* 测试服务层批量保存
*/
    @Test
    public void test06(){
    User u01=new User();
    u01.setRealName("zhangsan");
    u01.setPassword("123456");
    u01.setAge(23);
    u01.setEmail("[email protected]");
    u01.setName("张三");
    User u02=new User();
    u02.setRealName("lisi");
    u02.setPassword("123456");
    u02.setAge(24);
    u02.setEmail("[email protected]");
    u02.setName("李四");
    boolean isSuccess =
    userService.saveBatch(Arrays.asList(u01, u02));
    System.out.println(isSuccess?"保存成功":"保存失败");
}
/*
*根据id删除操作
*/
    @Test
    public void test07(){
    boolean isSuccess = userService.removeById(14L);
    System.out.println(isSuccess?"保存成功":"保存失败");
}
/**
* @Description 根据条件批量删除
*/
    @Test
    public void test08(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.gt("id",12)
    .gt("age",20);
    boolean remove = userService.remove(wrapper);
    System.out.println(remove);
}
/*
*测试根据id更新数据
*/
    @Test
    public void test09(){
    User user=new User();
    user.setId(12L);
    user.setRealName("lisi");
    user.setPassword("123456");
    user.setAge(24);
    user.setEmail("[email protected]");
    user.setName("李四");
    boolean success = userService.updateById(user);
    System.out.println(success);
}

五.MP代码生成器


5.1 MP逆向工程介绍

开发中当有一个新的业务要实现时,通常我们需要构建一下信息:
        *定义PO类
数据库表和实体类的映射 Java Bean,打各种mp的注解。
        *定义DAO层
需要编写接口 Mapper ,接口 Mapper 需要去继承 MP 中的 BaseMapper 接口。
        *定义Service层
编写 Service 层接口和实现类。
业务接口需要去继承 MP 中的 IService,业务实现类需要继承 MP 中的 ServiceImpl
和 实现业务接口。
        *定义Controller层
编写 Controller 并标注 Spring MVC 中的相关注解。
显然上述存在固定的流程,且存在大量重复操作,you now 代码价值低且没效率!

5.2 基于MybatisX实现逆向工程

六.逻辑删除

实际在删除数据时,为了数据留痕,一般选择逻辑删除,也就是为删除表添加逻辑删
除字段,通过修改字段状态值来表示数据是否被删除;

为tb_user添加逻辑删除字段:

mp配置:

# 设置mp运行时行为
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台
输出sql
global-config:
db-config:
logic-delete-field: deleted # 指定逻辑删除的表的列名
logic-delete-value: 1 # 指定删除的成功后字段的值
logic-not-delete-value: 0 # 指定没有删除的字段的值
 

调整实体类:

@Data
@NoArgsConstructor//主要用于mybatis底层反射构建user实体类对象
@AllArgsConstructor//主要是lombok基于构建者模式构建对象
@Builder
/**
* 如果变的名称与实体类名称一致,该注解可省略
*/
    @TableName("tb_user")
    public class User {
    //......
    @TableLogic//指定逻辑删除字段
    private Integer deleted;
}

测试:

@Test
public void testDelete(){
    //根据id删除
    int count = userMapper.deleteById(15l);
    System.out.println(count);
}

但是对应的查询如果不加添加,则删除的无法查询到:

@Test
public void testGetById(){
User user = userMapper.selectById(15l);
System.out.println(user);
}

逻辑删除本质就是拦截sql,动态追加sql片段

        查询 deleted=0
删除: 将sql转化成update操作;

;