MyBatis Plus

目录

一、概述

1.1 简介

1.2 特点

二、整体介绍

三、入门案例

3.1 环境搭建

3.2 数据库和表 

3.3 入门案例

四、基本操作 - BaseMapper

4.1 BaseMapper概述

4.2 常用方法

五、查询

六、分页

6.1 内置插件

6.2 配置类 MybatisPlusConfig

6.3 分页查询

七、常见注解

7.1 表名注解 @TableName

7.2 主键注解 @TableId

7.3 字段注解(非主键)@TableFiled

八、常见配置

九、高级(插件机制)

9.1 自动填充

9.2 乐观锁

9.3 逻辑删除

十、通用service

十一、新功能

11.1 执行SQL分析打印

11.2 数据安全保护


一、概述

  • 将Mybatis + 通用Mapper + PageHelper升级成 MyBatis Plus
1.1 简介

官网:MyBatis-Plus

MyBatis-Plus(简称  MP)是一个 MyBatis 的增强工具,在 MyBatis  的基础上只做增强不做改变,为简化开发、提高效率而生。

1.2 特点
  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的  CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD  操作,更有强大的条件构造器,满足各类使用需求
  • 支持  Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持多种数据库:支持  MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer2005、SQLServer  等多种数据库
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID  生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 XML  热加载:Mapper 对应的 XML 支持热加载,对于简单的 CRUD 操作,甚至可以无 XML  启动
  • 支持  ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD  操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once,  use anywhere )
  • 支持关键词自动转义:支持数据库关键词(order、key......)自动转义,还可自定义关键词
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成  Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis  物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 内置性能分析插件:可输出 Sql  语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update  操作智能分析阻断,也可自定义拦截规则,预防误操作
  • 内置 Sql  注入剥离器:支持 Sql 注入剥离,有效预防 Sql 注入攻击
select * from user where username = 'jack' and password = '1234';
-- 将 jack 替换成 jack' #
-- sql注入,用户输入的内容,称为sql语句语法的一部分。
select * from user where username = 'jack' #' and password = '1234';

二、整体介绍

三、入门案例

3.1 环境搭建

步骤:

  1. 创建项目
  2. 修改pom.xml文件,添加依赖
<!--确定spring boot的版本-->
<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.3.5.RELEASE</version>
</parent>   
<dependencies>
    <!-- web 开发 -->
    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--MySQL数据库驱动-->
    <dependency>
    	<groupId>mysql</groupId>
    	<artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!--支持lombok-->
    <dependency>
    	<groupId>org.projectlombok</groupId>
    	<artifactId>lombok</artifactId>
    </dependency>
    <!--测试-->
    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
    <dependency>
    	<groupId>com.baomidou</groupId>
    	<artifactId>mybatis-plus-boot-starter</artifactId>
    	<version>3.4.0</version>
    </dependency>
</dependencies>
  1. 创建application.yml文件,配置相关数据库信息
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/cloud_db1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC

#此处serverTimezone=UTC 的UTC值可以修改为GMT%2B8 用于修改数据库中时间的时区为东八区 时间+8小时
    username: root
    password: 25692569
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  #输出日志

注意:此时cj.jdbc.Driver可能会爆红

报错为Cannot resolve class 'Driver'

如下图:

该原因为上方步骤2中MySQL版本配置错误,可能版本太高,也可能版本太低

我之前设置的是5.1.32版本,然后我换成8.0.13版本就好了,如果该版本还不能解决,可多试几个版本

3.2 数据库和表 
CREATE DATABASE cloud_db1;
USE cloud_db1;
CREATE TABLE `tmp_customer` (
  `cid` INT(11) NOT NULL AUTO_INCREMENT,
  `cname` VARCHAR(50) DEFAULT NULL,
  `password` VARCHAR(32) DEFAULT NULL,
  `telephone` VARCHAR(11) DEFAULT NULL,
  `money` DOUBLE DEFAULT NULL,
  `version` INT(11) DEFAULT NULL,
  `create_time` DATE DEFAULT NULL,
  `update_time` DATE DEFAULT NULL,
  PRIMARY KEY (`cid`)
);

INSERT  INTO `tmp_customer`(`cid`,`cname`,`password`,`telephone`,`money`,`version`,`create_time`,`update_time`) 
VALUES (1,'jack','1234','110',1000,NULL,'2023-12-07',NULL),(2,'rose','1234','112',1000,NULL,'2023-12-08',NULL),(3,'tom','1234','119',1000,NULL,'2023-12-09',NULL);
3.3 入门案例

项目结构如下:

步骤:

  1. 配置JavaBean,添加MyBatisPlus所对应的注解(表、主键、字段等)
@Data
@TableName(value = "tmp_customer")
public class Customer {
    @TableId(type = IdType.AUTO)
    private Integer cid;
    private String cname;
    private String password;
    private String telephone;
    private Double money;

    private Integer version;

    private Date createTime;
    private Date updateTime;
}
  1. 编写dao层,并继承BaseMapper接口
@Mapper
public interface CustomerMapper extends BaseMapper<Customer> {
}
  1. 编写启动类
@SpringBootApplication
public class MybatisPlusApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusApplication.class, args);
    }
}
  1. 编写测试类
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MybatisPlusApplication.class)
public class TestDemo01 {
    @Resource
    private CustomerMapper customerMapper; 
    /*
    * 查询所有
    * */
    @Test
    public void testFindAll() {
        List<Customer> customers = customerMapper.selectList(null);

        customers.forEach(System.out::println);
    }
}

四、基本操作 - BaseMapper

4.1 BaseMapper概述

BaseMapper 接口是基于 MyBatis 框架的通用 Mapper 插件提供的一个接口。该接口定义了一些通用的数据访问方法,用于对数据库进行增删改查操作。BaseMapper 接口使用了泛型来指定实体类的类型,从而实现了对不同实体类的通用操作。

4.2 常用方法

增删改:

方法名

描述

int insert(T entity)

插入一条记录,entity 为 实体对象

int delete(Wrapper<T> wrapper)

根据 entity 条件,删除记录,wrapper 可以为 null

int deleteBatchIds(Collection idList)

根据ID 批量删除

int deleteById(Serializable id)

根据 ID 删除

int deleteByMap(Map<String, Object> map)

根据 columnMap 条件,删除记录

int update(T entity, Wrapper<T> updateWrapper)

根据 whereEntity 条件,更新记录

int updateById(T entity);

根据 ID 修改

查询:

方法名

描述

T selectById(Serializable id)

根据 ID 查询

T selectOne(Wrapper<T> queryWrapper)

根据 entity 条件,查询一条记录

List<T> selectBatchIds(Collection idList)

根据ID 批量查询

属性

描述

value

表名

keepGlobalPrefix

是否保持使用全局的 tablePrefix 的值(如果设置了全局 tablePrefix 且自行设置了 value 的值)

List<Object> selectObjs( Wrapper<T> queryWrapper)

根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值

IPage<T> selectPage(IPage<T> page, Wrapper<T> queryWrapper)

根据 entity 条件,查询全部记录(并翻页)

IPage<Map<String, Object>> selectMapsPage(IPage<T> page, Wrapper<T> queryWrapper)

根据 Wrapper 条件,查询全部记录(并翻页)

Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper)

根据 Wrapper 条件,查询总记录数

	/*
     * 添加
     * */
    @Test
    public void insert() {
        Customer customer = new Customer();
        customer.setCname("张三");
        customer.setPassword("1234");
        customer.setTelephone("123456789");
        customer.setMoney(1000.0);

        int insert = customerMapper.insert(customer);

        if (insert == 1) {
            System.out.println("添加成功");
        } else {
            System.out.println("添加失败");
        }

        System.out.println(insert);
    }
	/*
     * 更新
     * */
    @Test
    public void update() {
        Customer customer = new Customer();
        customer.setCid(4);
        customer.setCname("李四");
        customer.setPassword("12345");
        customer.setTelephone("15963758033");

        int update = customerMapper.updateById(customer);

        if (update == 1) {
            System.out.println("修改成功");
        } else {
            System.out.println("修改失败");
        }
    }
    /*
     * 删除
     * */
    @Test
    public void delete() {
        int deleteById = customerMapper.deleteById(4);

        if (deleteById == 1) {
            System.out.println("删除成功");
        } else {
            System.out.println("删除失败");
        }
    }

五、查询

5.1 wrapper条件

Wrapper 是 MyBatis-Plus 提供的一个条件构造器,用于构建复杂的查询条件。它可以通过链式调用的方式,方便地拼接各种条件,实现灵活的查询功能。

  • Wrapper : 条件构造抽象类,最顶端父类
    • AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
      • QueryWrapper : Entity 对象封装操作类,不是用lambda语法
      • AbstractLambdaWrapper : Lambda 语法使用 Wrapper统一处理解析 lambda 获取 column。
      • UpdateWrapper : Update 条件封装,用于Entity对象更新操作
        • LambdaQueryWrapper :看名称也能明白就是用于Lambda语法使用的查询Wrapper
        • LambdaUpdateWrapper : Lambda 更新封装Wrapper

 如果想进行复杂条件查询,那么需要使用条件构造器 Wapper,涉及到如下方法

方法名

描述

selectOne

根据条件查询一个,结果:0或1,如果查询多个异常

selectCount

查询总条数

selectList

查询所有

selectMaps

将一条记录封装到Map中,最后返回List<Map<Sting,Object>>

selectObjs

将一条记录封装到Object中,最后返回List<Object>

update

更新指定条件

delete

删除指定条件

拼凑条件相关关键字

查询方式

说明

setSqlSelect

设置 SELECT 查询字段

where

WHERE 语句,拼接 + WHERE 条件

and

AND 语句,拼接 + AND 字段=值

andNew

AND 语句,拼接 + AND (字段=值)

or

OR 语句,拼接 + OR 字段=值

orNew

OR 语句,拼接 + OR (字段=值)

eq

等于=

allEq

基于 map 内容等于=

ne

不等于<>

gt

大于>

ge

大于等于>=

lt

小于<

le

小于等于<=

like

模糊查询 LIKE

notLike

模糊查询 NOT LIKE

in

IN 查询

notIn

NOT IN 查询

isNull

NULL 值查询

isNotNull

IS NOT NULL

groupBy

分组 GROUP BY

having

HAVING 关键词

orderBy

排序 ORDER BY

orderAsc

ASC 排序 ORDER BY

orderDesc

DESC 排序 ORDER BY

exists

EXISTS 条件语句

notExists

NOT EXISTS 条件语句

between

BETWEEN 条件语句

notBetween

NOT BETWEEN 条件语句

addFilter

自由拼接 SQL

last

拼接在最后,例如:last(“LIMIT 1”)

5.2 条件查询

    /*
     * 条件查询
     * */
    @Test
    public void testWrapper() {
        // 拼接条件
        QueryWrapper<Customer> queryWrapper = new QueryWrapper<>();

        // 姓名:查询名字中包含o的数据   模糊查询 --- 参数1:列名, 参数2:查询的值
        queryWrapper.like("cname", "o");

        // 等值查询
        queryWrapper.eq("telephone", "123");

        // 批量查询
        queryWrapper.in("cid", 1, 3);

        // 范围查询
        queryWrapper.ge("create_time", "2023-12-7");
        queryWrapper.le("create_time", "2023-12-7");
        // 查询
        List<Customer> l/dmkist = customerMapper.selectList(queryWrapper);
        customerList.forEach(System.out::println);
    }
    @Test
    public void testFindCondition() {
        Customer customer = new Customer();
        customer.setPassword("777");
        customer.setCname("888");
        customer.setIdList(Arrays.asList(2,3,4));
        customer.setCid(3);
        //条件查询
        QueryWrapper<Customer> queryWrapper = new QueryWrapper<>();
        // 1) 等值查询
        queryWrapper.eq(customer.getPassword()!=null ,"password", customer.getPassword());
        // 2) 模糊查询
        queryWrapper.like(customer.getCname() != null , "cname",customer.getCname());
        // 3) in语句
        queryWrapper.in(customer.getIdList() != null , "cid",customer.getIdList());
        // 4) 大于等于
        queryWrapper.ge(customer.getCid() != null , "cid" , customer.getCid());

        //查询
        List<Customer> list = customerMapper.selectList(queryWrapper);
        //list.forEach(customer-> System.out.println(customer));
        list.forEach(System.out::println);
    }

5.3 条件更新

    /*
    * 条件更新
    * */
    @Test
    public void testUpdateWrapper() {
        // 待更新数据
        Customer customer = new Customer();
        customer.setVersion(10);

        // 更新条件
        UpdateWrapper<Customer> updateWrapper = new UpdateWrapper<>();
        updateWrapper.in("cid", 1,2);

        // 更新
        int update = customerMapper.update(customer, updateWrapper);

        if(update != 1) {
            System.out.println("更新成功");
        }else {
            System.out.println("更新失败");
        }
    }

六、分页

6.1 内置插件

主体插件: MybatisPlusInterceptor,该插件内部插件集:

  • 分页插件: PaginationInnerInterceptor
  • 多租户插件: TenantLineInnerInterceptor
  • 动态表名插件: DynamicTableNameInnerInterceptor
  • 乐观锁插件: OptimisticLockerInnerInterceptor
  • sql性能规范插件: IllegalSQLInnerInterceptor
  • 防止全表更新与删除插件: BlockAttackInnerInterceptor
6.2 配置类 MybatisPlusConfig

创建/config/MybatisPlusConfig类

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {

    /**
     * 配置插件
     * @return
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){

        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        // 分页插件
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));

        return mybatisPlusInterceptor;
    }

    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
     * @return
     */
    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return configuration -> configuration.setUseDeprecatedExecutor(false);
    }
}
6.3 分页查询
   /*
    * 分页查询
    * */
    @Test
    public void testPage() {
        // 分页条件
        int pageNum = 1;        // 当前页
        int pageSize = 2;       // 当前页所有数据

        // 拼接分页条件
        Page<Customer> page = new Page<>(pageNum, pageSize);
        page.setSearchCount(true);      // 开启总记录数查询

        customerMapper.selectPage(page,null);

        System.out.println("总记录数:" + page.getTotal());
        System.out.println("当前页:" + page.getCurrent());
        System.out.println("查询结果:" + page.getRecords());
        System.out.println("每页显示记录数:" + page.getSize());

        System.out.println("总页数:" + page.getPages());
        System.out.println("是否有下一页:" + page.hasNext());
        System.out.println("是否有上一页:" + page.hasPrevious());
    }

七、常见注解

7.1 表名注解 @TableName

属性

描述

value

表名

keepGlobalPrefix

是否保持使用全局的 tablePrefix 的值(如果设置了全局 tablePrefix 且自行设置了 value 的值)

7.2 主键注解 @TableId

属性

描述

value

主键字段名

type

主键类型 IdType.ASSIGN_UUID ,分配UUID,MyBatisPlus维护String数据 IdType.ASSIGN_ID ,分配ID(默认使用雪花算法)MyBatisPlus维护Long数据 IdType.AUTO ,自动增长(数据库维护)

7.3 字段注解(非主键)@TableFiled

属性

描述

value

数据库列名

fill

字段自动填充策略 FieldFill.INSERT 插入时填充字段 FieldFill.UPDATE 更新时填充字段 FieldFill.INSERT_UPDATE 插入和更新时填充字段

exist

是否存储到数据库(是否是临时数据)

八、常见配置

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  #输出日志
    map-underscore-to-camel-case: true  #驼峰命名
  global-config:
    db-config:
      id-type: auto  #全局配置,id自动增强
      table-prefix: tmp_ #表名前缀
  type-aliases-package: com.czxy.mp.domain #别名包扫描路径
  mapper-locations: classpath*:/mapper/**/*.xml #映射文件位置
// value 表名
// keepGlobalPrefix 用于控制是否保持全局的前缀

// 修改之前
@TableName(value = "tmp_customer")
// 修改之后
@TableName(value = "customer",keepGlobalPrefix = true)
// 如果类名和表名一样,还可简略
@TableName(keepGlobalPrefix = true)

整合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.czxy.mp.mapper.CustomerMapper">

  <select id="findAll" resultType="customer">
    select * from tmp_customer
  </select>

</mapper>

CustomerMapper对应的方法:

@Mapper
public interface CustomerMapper extends BaseMapper<Customer> {
    // 自定义查询所有
    public List<Customer> findAll();
}

九、高级(插件机制)

9.1 自动填充

MyBatis-Plus 的自动填充功能是一种方便开发者的特性,它可以在执行插入(insert)或更新(update)操作时,自动为某些字段填充值,从而减少了手动设置这些字段值的需要。

原理:

  • 实现元对象处理器接口:com.baomidou.mybatisplus.core.handlers.MetaObjectHandler,确定填充具体操作
  • 注解填充字段:@TableField(fill = ...) 确定字段填充的时机
    • FieldFill.INSERT:插入填充字段
    • FieldFill.UPDATE:更新填充字段
    • FieldFill.INSERT_UPDATE:插入和更新填充字段

自动填充通常用于如下场景:

  1. 创建时间和修改时间:在数据库表中,我们经常需要记录数据的创建时间和最后修改时间。使用自动填充功能,每次插入或更新数据时,MyBatis-Plus 可以自动为这两个字段设置当前时间。
  2. 创建者或修改者:在多用户系统中,记录数据的创建者或最后修改者是有意义的。通过自动填充功能,可以自动设置这两个字段的值为当前登录的用户ID。

如何使用:

  1. 定义填充处理器:首先,你需要定义一个实现了 MetaObjectHandler 接口的类,这个类负责为目标字段提供填充的值。
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        // 设置创建时间
        this.setFieldValByName("createTime",new Date(), metaObject);

        // 设置更新时间
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        // 设置更新时间
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }
}
  1. 在实体类上标注需要自动填充的字段:使用 @TableField 注解标注需要自动填充的字段,并指定填充策略。
@Data
//@TableName(value = "tmp_customer")
@TableName(value = "customer",keepGlobalPrefix = true)
public class Customer {
    @TableId(type = IdType.AUTO)
    private Integer cid;
    private String cname;
    private String password;
    private String telephone;
    private Double money;
    private Integer version;

    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
}

通过以上步骤,当执行插入或更新操作时,MyBatis-Plus 会自动为指定的字段填充值,从而简化了开发过程。

9.2 乐观锁

MyBatis-Plus 是一个基于 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,简化开发、提高效率。乐观锁是 MyBatis-Plus 提供的一种乐观锁机制,用于实现数据的版本控制。

  • 目的:数据必须同步。当要更新一条记录的时候,希望这条记录没有被别人更新
  • 乐观锁实现方式:(万一发生了数据不一致的解决方案)
  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败

实现:

1:修改JavaBean

    @Version
    @TableField(fill = FieldFill.INSERT)
    private Integer version;

2:在MetaObjectHandler 类中添加version的insert默认值 (保证version有数据)

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        // 设置创建时间
        this.setFieldValByName("createTime",new Date(), metaObject);

        // 设置更新时间
        this.setFieldValByName("updateTime", new Date(), metaObject);

        // 设置版本号
        this.setFieldValByName("version", 1, metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        // 设置更新时间
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }
}

3:修改MybatisPlusConfig中开启乐观锁

@Configuration
public class MybatisPlusConfig {
     */
    /**
     * 配置插件
     * @return
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){

        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        // 分页插件
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        // 乐观锁
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());

        return mybatisPlusInterceptor;
    }
}

4:更新操作

    /*
     * 更新
     * */
    @Test
    public void update() {
        Customer customer = new Customer();
        customer.setCid(4);
        customer.setCname("李四");
        customer.setPassword("12345");
        customer.setTelephone("15963758033");
        // 与数据库中数据一致,将更新成功,否则返回失败。
        customer.setVersion(0);

        int update = customerMapper.updateById(customer);

        if (update == 1) {
            System.out.println("修改成功");
        } else {
            System.out.println("修改失败");
        }
    }

注意事项:

  1. 支持的数据类型只有:int、integer、long、Long、Date、Timestamp、LocalDateTime
  2. 整数类型下 newVersion = oldVersion + 1
  3. newVersion会写回到entity中
  4. 仅支持updateById(id)与update(entity, wrapper)方法
  5. 在update(entity, wrapper)方法下,wrapper不能复用
  6. 数据库表的version字段,必须有默认值(SQL语句默认值、MyBatisPlus自动填充)
  7. 在进行更新操作时,必须设置version值,否则无效
9.3 逻辑删除
  • 逻辑删除,也称为假删除。就是在表中提供一个字段用于记录是否删除,实际该数据没有被删除。

步骤:

1:在数据库中提供一个字段deleted,默认值为0

alter table tmp_customer add column deleted int default 0;

2:在JavaBean中添加deleted,并为其添加@TableField(fill = FieldFill.INSERT)和@TableLogic标识

@TableLogic         // 逻辑删除
@TableField(fill = FieldFill.INSERT)
private Integer deleted;

3:添加数据时,设置默认“逻辑未删除值”

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        // 设置创建时间
        this.setFieldValByName("createTime",new Date(), metaObject);

        // 设置更新时间
        this.setFieldValByName("updateTime", new Date(), metaObject);

        // 设置版本号
        this.setFieldValByName("version", 1, metaObject);

        // 逻辑删除
        this.setFieldValByName("deleted", 1, metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        // 设置更新时间
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }
}

4:测试

    @Test
    public void testDelete() {
        // 删除时,必须保证deleted数据为“逻辑未删除值”
        int i = customerMapper.deleteById(12);
        System.out.println(i);
    }

注意:

  • 如果使用逻辑删除,将delete语句,修改成了update,条件 where deleted=0
  • 同时,查询语句自动追加一个查询条件 WHERE deleted=0。如果查询没有数据,检查deleted字段的值。

全局配置:

如果配置了全局配置可以不使用注解@TableLogic

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted  # 局逻辑删除的实体字段名
      logic-delete-value: 1  # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

恢复:

  • 问题:进行逻辑删除后的数据,如何恢复(recovery)?
    • 需要自己编写SQL语句
  • 方案1:使用sql具有,更新deleted=0即可
UPDATE `tmp_customer` SET `deleted`='0' WHERE `cid`='13';

方案2:修改Mapper,添加 recoveryById 方法,进行数据恢复。

@Mapper
public interface CustomerMapper extends BaseMapper<Customer> {

    @Update("update tmp_customer set deleted = 0 where cid = #{cid}")
    public void recoveryById(@Param("cid") Integer cid);
}

十、通用service

标准service:接口+实现

service接口:

public interface CustomerService extends IService<Customer> {
    // 查询所有
    public List<Customer> selectAll();
}

service实现类:

@Service
@Transactional
public class CustomerServiceImpl extends ServiceImpl<CustomerMapper, Customer> implements CustomerService {
    @Resource
    private CustomerMapper customerMapper;

    @Override
    public List<Customer> selectAll() {
        List<Customer> customerList = customerMapper.selectAll();
        return customerList;
    }
}

十一、新功能

11.1 执行SQL分析打印

该功能依赖p6spy组件,完美的输出打印SQL及执行时长

导入p6spy依赖

<dependency>
  <groupId>p6spy</groupId>
  <artifactId>p6spy</artifactId>
  <version>3.9.1</version>
</dependency>

核心yml配置:

spring:
  datasource:
#    driver-class-name: com.mysql.cj.jdbc.Driver
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver
    url: jdbc:mysql://localhost:3306/cloud_db1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
    username: root
    password: 25692569

spy.properties配置:

#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2
11.2 数据安全保护

为了保护数据库配置及数据安全,在一定的程度上控制开发人员流动导致敏感信息泄露

步骤1:使用工具类生成密钥以及对敏感信息进行加密

import com.baomidou.mybatisplus.core.toolkit.AES;
import org.junit.Test;

public class TestAES {
    @Test
    public void testAes() {
        String randomKey = AES.generateRandomKey();

        String url =  "jdbc:p6spy:mysql://localhost:3306/cloud_db1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8";
        String username = "root";
        String password = "25692569";

        String urlAES = AES.encrypt(url, randomKey);
        String usernameAES = AES.encrypt(username, randomKey);
        String passwordAES = AES.encrypt(password, randomKey);

        System.out.println("--mpw.key=" + randomKey);
        System.out.println("mpw:" + urlAES);
        System.out.println("mpw:" + usernameAES);
        System.out.println("mpw:" + passwordAES);
    }
}
// Jar 启动参数( idea 设置 Program arguments , 服务器可以设置为启动环境变量 )
//--mpw.key=9fb2d1adad680c88
//mpw:ypzCnzkilli+k4juL3slgtkGzc1blEVjkleDdSWYu66q6D49lzjWF1yEK1CmkxLWKOs+kQRZO/LwbJHWs0Y4pEDKmVnUjn2PNbPvkdTojTm9307/dtBddsXpSfgfmRAtM7sRAhQBtrVgAOIq4PjURw==
//mpw:44Q9C/85iTfaPdPilqYe2w==
//mpw:LhIFrlePhMdd30D+sIOrEw==

步骤2:配置加密信息

步骤3:使用密钥启动服务

注意:

步骤4:如果想在测试文件上使用在@SpringBootTest(classes="启动类",args={"密钥"})

总之,MybatisPlus是一款高效、简洁、易用且功能强大的Mybatis增强工具,适用于各种类型的Java项目。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值