MybatisPlus核心知识点

主要学习内容

  • 配置日志输出
  • 插入数据及雪花算法
  • 主键策略
  • 自动填充
  • 乐观锁(version)
  • 分页查询
  • 逻辑删除
  • 性能分析插件
  • 条件查询器Wrapper
  • 代码自动生成器
  • 数据安全保护

前置资料

本次学习使用到的的数据库SQL脚本

CREATE DATABASE `mybatis-plus` CHARSET utf8;

USE `mybatis-plus`;

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user`
(
    `id` BIGINT(20) NOT NULL COMMENT '主键ID',
    `name` VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
    `age` INT NULL DEFAULT 0 COMMENT '年龄',
    `email` VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
    PRIMARY KEY(id)
)ENGINE INNODB CHARSET utf8;


INSERT INTO USER (id ,NAME, age, email) VALUES 
(1, 'Jone', 18, 'test@baomidou.com'),
(2, 'Jack', 20, 'abc@baomidou.com'),
(3, 'Tom', 19, 'cccc@baomidou.com'),
(4, 'Sandy', 28, 'xiao@baomidou.com'),
(5, 'Billie', 24, 'meimei@baomidou.com');

与Mybatis-Plus相关的jar依赖

        <!-- 添加mybatis-plus依赖 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>
        <!-- Mybatis-Plus代码自动生成器 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.4.1</version>
        </dependency>

<!-- 添加 模板引擎 依赖,MyBatis-Plus 支持 Velocity(默认) --> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.1</version> </dependency> <!-- 数据库驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- 引入swagger --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency>

1、配置日志输出

只需要在springboot核心配置文件中配置下面一行代码即可

# 配置日志输出
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

2、自动填充——三步(注意:填充原理是直接给entity的属性设置值,而不是数据库表中的字段!!!)

1、编写一个类实现MetaObjectHandler接口,并重写该接口的两个方法insertFill() 和 updateFill()

 1 package com.lzp.intercept;
 2 
 3 import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
 4 import lombok.extern.slf4j.Slf4j;
 5 import org.apache.ibatis.reflection.MetaObject;
 6 import org.springframework.stereotype.Component;
 7 import java.util.Date;
 8 
 9 /**
10  * @Author LZP
11  * @Date 2021/7/13 14:29
12  * @Version 1.0
13  *
14  * 填充原理是直接给entity的属性设置值!!!
15  */
16 @Slf4j
17 @Component
18 public class MyMetaObjectHandler implements MetaObjectHandler {
19     @Override
20     public void insertFill(MetaObject metaObject) {
21         log.info("start insert fill ....");
22         Date cur = new Date();
23         this.setFieldValByName("createTime", cur, metaObject);
24         this.setFieldValByName("updateTime", cur, metaObject);
25     }
26 
27     @Override
28     public void updateFill(MetaObject metaObject) {
29         log.info("start update fill ....");
30         Date cur = new Date();
31         this.setFieldValByName("updateTime", cur, metaObject);
32     }
33 }

2、在实体类指定要填充的字段上面加上@TableField这个注解,并指明要填充的类型(即在什么操作下才去填充这个字段)

 

3、测试

1)测试前数据

 2)执行测试代码

 1 // 自动填充
 2 @Test
 3 void autoFull() {
 4     User user = new User();
 5     user.setId(1414828510853300227L);
 6     user.setName("赵敏");
 7     user.setAge(40);
 8     user.setEmail("zm@qq.com");
 9     userMapper.updateById(user);
10 }

3)测试后数据

3、乐观锁(OptimisticLockerInnerInterceptor)

乐观锁配置需要两步

1)配置插件

spring.xml方式

<bean class="com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor" id="optimisticLockerInnerInterceptor"/>

<bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor">
    <property name="interceptors">
        <list>
            <ref bean="optimisticLockerInnerInterceptor"/>
        </list>
    </property>
</bean>

spring boot注解方式

/**
 * 旧版
 */
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
    return new OptimisticLockerInterceptor();
}

/**
 * 新版
 */
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
    mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
    return mybatisPlusInterceptor;
}

2)先在数据表中添加version字段,然后在对应的实体类中也添加version字段,最后在实体类的字段上加上 @Version 注解

3)测试

测试前,查看一下数据库表user

执行测试代码

 1 // 乐观锁
 2 @Test
 3 void optimisticLock() {
 4     // 需要在数据库表中添加一个version字段
 5 
 6     /*
 7         模拟乐观锁:当一个用户在操作某一行时,在这中间由于网络延迟等原因,让
 8         另外一个线程插队了,另外一个线程执行完后,当前线程才执行。这种情况下
 9         我们为了避免多线程安全问题,则不允许当前线程再继续对当前行数据操作,
10         即当前线程的操作失效
11      */
12     // 线程1
13     // 注意:这里一定要先查询一下即将要修改的用户(不查的话一开始就拿不到版本号,也就不能通过版本号来作为条件判断是否有线程插队)
14     User user = userMapper.selectById(1414828510853300227L);
15     user.setAge(41);
16 
17     // 中间来了另外一个线程2
18     User user2 = userMapper.selectById(1414828510853300227L);
19     user2.setName("赵敏");
20     userMapper.updateById(user2);
21 
22     // 如果没有乐观锁,值就会被覆盖
23     userMapper.updateById(user);
24 }

运行结果:

数据库表

控制台

4、分页查询

1)第一步:配置分页拦截器组件

2)直接使用Page对象测试即可

 1 // 分页
 2 @Test
 3 void limitPage() {
 4     // 构造器 ==> public Page(long current, long size)
 5     // current:当前页
 6     // size:页面大小
 7     Page<User> page = new Page<>(1, 5);
 8     IPage<User> userIPage = userMapper.selectPage(page, null);
 9     userIPage.getRecords().forEach(System.out::println);
10 }

3)测试效果

5、逻辑删除

定义

物理删除:从数据库中直接移除

逻辑删除:在数据库中没有被移除,而是通过一个变量让它失效(即正常的查询查询不到)

应用场景

管理员可以查看已经被删除的记录!防止数据的丢失,类似于回收站

实现步骤

1)在数据库表中增加一个deleted字段

修改表

添加新字段

效果如下:

2)在实体类中增加deleted属性

// 逻辑删除
@TableLogic
private Integer deleted;

3)配置逻辑删除组件

 

// 配置逻辑删除组件
@Bean
public ISqlInjector sqlInjector() {
    return new LogicSqlInjector();
}

4)在springboot全局配置文件中配置逻辑删除

# 配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

5)测试

删除前

执行逻辑删除代码

// 逻辑删除
@Test
void logicDeleted() {
    userMapper.deleteById(1L);
}

删除后

数据库表

6、性能分析插件

配置PerformanceInterceptor拦截器

 1 /**
 2  * SQL执行效率插件
 3  */
 4 @Bean
 5 @Profile({"dev", "test"}) // 设置dev、test环境开启,保证我们的效率
 6 public PerformanceInterceptor performanceInterceptor() {
 7     PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
 8     // 设置sql执行的最大时间,如果超过了则不执行,单位ms
 9     performanceInterceptor.setMaxTime(1000);
10     // 是否开启SQL格式化支持
11     performanceInterceptor.setFormat(true);
12     return performanceInterceptor;
13 }

7、条件查询器Wrapper

直接使用BaseMapper里面提供的方法即可(用带Wrapper参数的方法),这里用的是selectList()方法,选用的是QueryWrapper

@Test
void conditionQueryWrapper() {
    // Wrapper以下有两个常用的实现类:QueryWrapper 和 UpdateWrapper
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    // 年龄大于等于20
    queryWrapper.ge("age", 20);
    // 姓名中不包含字母a
    queryWrapper.notLike("name", "a");
    // 创建时间为空
    queryWrapper.isNull("create_time");
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.out::println);
}

测试结果

1)控制台输出

8、代码自动生成器

模板代码如下:

package com.lzp;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.LikeTable;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.List;

@SpringBootTest
class MybatisPlusNetshopApplicationTests {

    // 代码生成器模板
    @Test
    void contextLoads() {
        // 构造一个AutoGenerator
        AutoGenerator autoGenerator = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("LZP");
        gc.setOpen(false);
        // 是否覆盖
        gc.setFileOverride(true);
        // 去Service的I前缀
        gc.setServiceName("%sService");
        gc.setDateType(DateType.ONLY_DATE);
        gc.setSwagger2(true);
        autoGenerator.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/netshop?useUnicode=true&useSSL=false&characterEncoding=utf-8");
        dataSourceConfig.setDriverName("com.mysql.jdbc.Driver");
        dataSourceConfig.setUsername("root");
        dataSourceConfig.setPassword("123");
        dataSourceConfig.setDbType(DbType.MYSQL);
        autoGenerator.setDataSource(dataSourceConfig);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("netshop");
        pc.setParent("com.lzp");
        pc.setController("controller");
        pc.setService("service");
        pc.setMapper("mapper");
        pc.setEntity("pojo");
        autoGenerator.setPackageInfo(pc);

        // 配置模板 目的:删除在/src/main/java目录下的mapper里生成的xml目录
        TemplateConfig templateConfig = new TemplateConfig();

        // 配置自定义输出模板
        //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
        // templateConfig.setEntity("templates/entity2.java");
        // templateConfig.setService();
        // templateConfig.setController();

        templateConfig.setXml(null);
        autoGenerator.setTemplate(templateConfig);

        /*
            需求:
                将mapper文件放入到我们的resources资源路径下,方便资源统一管理
         */
        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };
        // 如果模板引擎是 freemarker
//        String templatePath = "/templates/mapper.xml.ftl";
        // 如果模板引擎是 velocity
        String templatePath = "/templates/mapper.xml.vm";
        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                return projectPath + "/src/main/resources/mapper/"
                        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(focList);
        autoGenerator.setCfg(cfg);


        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        // 逻辑删除
        strategy.setLogicDeleteFieldName("deleted");
        // 乐观锁
        strategy.setVersionFieldName("version");
        // 自动填充
        TableFill gmtCreate = new TableFill("create_time", FieldFill.INSERT);
        TableFill gmtUpdate = new TableFill("update_time", FieldFill.INSERT_UPDATE);
        List<TableFill> list = new ArrayList<>();
        list.add(gmtCreate);
        list.add(gmtUpdate);
        strategy.setTableFillList(list);
        // 在Controller控制器上加上@RestController注解
        strategy.setRestControllerStyle(true);
        /*
            @RequestMapping注解中的url格式设置 ==> 默认是驼峰命名 /user/userAdd
            开启连字符 ==> strategy.setControllerMappingHyphenStyle(true);
            /user/user_add
         */
        // 按前缀生成表
        strategy.setLikeTable(new LikeTable("tb_"));
        // 设置表替换前缀
        strategy.setTablePrefix("tb_");
        autoGenerator.setStrategy(strategy);


        // 执行
        autoGenerator.execute();
    }

}

生成后的项目目录结构

9、数据安全保护

所有配置文件展示

application.yaml

application-dev.yaml

application-pro.yaml

具体流程

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

⚪ 3.3.2 开始支持

依赖:

<!-- Mybatis-Plus -->
<dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.3.2</version>
</dependency>

⚪ 配置安全

YML 配置:

# 数据源配置
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: mpw:DdGxMC2nD0jM0yiwbRwu68yUztZr4VQB4+e3z8LEfgaxJ67RvXC92lLRFV2LiXpge2RHvyfhxt/kPSUcFByIbIvVpmGgWWCMDcx1iwnOJw1+N6eTkPoVYKmc9sMA2h+P
    username: mpw:ruFTzIubVYmKmWGFwGCK2g==
    password: mpw:elqQmbc0TpnxeJVfYU/dPA==

密钥加密:

// 获取一个16位的随机 AES 密钥
String randomKey = AES.generateRandomKey();
System.out.println("随机生成的一个16位AES密钥:" + randomKey);
// 加密
String url = AES.encrypt("jdbc:mysql://localhost:3306/mybatis-plus?useSSL=true&useUnicode=true&characterEncoding=utf-8", randomKey);
String username = AES.encrypt("root", randomKey);
String password = AES.encrypt("123", randomKey);
System.out.println("url对应的密文:" + url);
System.out.println("username对应的密文:" + username);
System.out.println("password对应的密文:" + password);

如何使用:

1、将项目打成jar包

2、打开jar包所在目录,并通过jar命令启动项目(要注意的是,现在我们项目已经打包,但是配置文件用的还是开发环境的配置文件dev,所以我们需要在命令行中加上:--spring.profiles.active=pro 来切换为生产环境)

而且,我们还需要通过密钥解密启动项目,因为在生产环境下的数据库的url、用户名、密码都是加密之后的,要想连接数据库则必须要有密钥才行

①没有通过密钥启动

详细信息

②加上密钥之后再启动,项目正常启动

 

 
 
 
 
 
 
 
 
posted @ 2021-07-13 16:34  没有你哪有我  阅读(148)  评论(0编辑  收藏  举报