谷粒学院--在线教育实战项目【一】

谷粒学院--在线教育实战项目【一】

  • 一、项目概述
    • 1.1.项目来源
    • 1.2.功能简介
    • 1.3.技术架构
  • 二、Mybatis-Plus概述
    • 2.1.简介
    • 2.2.特性
  • 三、Mybatis-Plus入门
    • 3.1.创建数据库
    • 3.2.创建 User 表
    • 3.3.初始化一个SpringBoot工程
    • 3.4.在Pom文件中引入SpringBoot和Mybatis-Plus相关依赖
    • 3.5.第一次使用lombok需要在IDEA中安装lombok插件
    • 3.6.MySQL 数据库的相关配置
    • 3.7.编写代码
      • 3.7.1.主类:
      • 3.7.2.实体类:
      • 3.7.3.mapper:
    • 3.8.开始使用
      • 3.8.1.查询所有用户,代码测试
      • 3.8.2.UserMapper(加注解)
      • 3.8.3.运行结果
    • 3.9.配置日志
  • 四、Mybatis-Plus相关操作
    • 4.1.插入操作【insert】
    • 4.2.主键生成策略
      • 4.2.1.ID_WORKER
      • 4.2.2.自增策略
    • 4.3.根据Id更新操作【update】
    • 4.4.自动填充
      • 4.4.1.数据库表中添加自动填充字段
      • 4.4.2.实体上添加注解
      • 4.4.3.测试添加数据
      • 4.4.4.测试结果
      • 4.4.5.自动填充策略FieldFill
      • 4.4.6.自定义实现类 MyMetaObjectHandler实现元对象处理器接口
      • 4.4.7.测试添加数据
      • 4.4.8.测试结果
    • 4.5.乐观锁
      • 4.5.1.表中添加version字段,作为乐观锁版本号
      • 4.5.2.实体类添加version属性
      • 4.5.3.元对象处理器接口添加version的insert默认值
      • 4.5.4.创建配置类MybatisPlusConfig 并注册 Bean
      • 4.5.5.测试乐观锁可以修改成功
      • 4.5.6.测试乐观锁修改失败
    • 4.6.select【查询】
      • 4.6.1.根据id查询记录
      • 4.6.2.通过多个id批量查询
      • 4.6.3.简单的条件查询
      • 4.6.4.分页
        • 4.6.4.1.创建配置类-添加分页插件
        • 4.6.4.2.测试selectPage分页
        • 4.6.4.3.测试selectMapsPage分页:结果集是Map
    • 4.7.delete【物理删除】
      • 4.7.1.根据id删除记录
      • 4.7.2.批量删除
      • 4.7.3.简单的条件查询删除
    • 4.8.【逻辑删除】
      • 4.8.1.数据库中添加 deleted字段
      • 4.8.2.实体类添加deleted 字段并加上 @TableLogic 逻辑删除注解
      • 4.8.3.元对象处理器接口添加deleted的insert默认值
      • 4.8.4.application.properties 加入配置
      • 4.8.5.测试逻辑删除
      • 4.8.6.测试逻辑删除后的查询
  • 五、性能分析
    • 5.1.配置插件
      • 5.1.1.参数说明
      • 5.1.2.在 MybatisPlusConfig 中配置
      • 5.1.3.自定义实现类 MyMetaObjectHandler
      • 5.1.4.Spring Boot 中设置dev环境
    • 5.2.测试
      • 5.2.1.常规测试
      • 5.2.2.将maxTime 改小之后再次进行测试
  • 六、条件构造器 Wrapper
  • endl 小技巧:护眼模式:CAE6CA、C7EDCC

一、项目概述

1.1.项目来源

谷粒学院在线教育平台采用B2C商业模式,使用前后端分离开发方式。项目包含后台管理系统前台用户系统,两个系统中分别包含后端接口部分和前端页面部分。

系统后端接口部分,使用目前流行的SpringBoot+SpringCloud进行微服务架构,使用Feign、Gateway、Hystrix,以及阿里巴巴的Nacos等组件搭建了项目的基础环境。项目中还使用MyBatisPlus进行持久层的操作,使用了OAuth2+JWT实现了分布式的访问,项目中整合了SpringSecurity进行了权限控制。除此之外,项目中使用了阿里巴巴的EasyExcel实现对Excel的读写操作,使用了Redis进行首页数据的缓存,使用Git进行代码的版本控制,还整合了Swagger生成接口文档 。

系统前端部分,使用主流的前端框架Vue,使用ES6的开发规范,采用模块化的开发模式,搭建页面环境使用了Nuxt框架和vue-admin-template模板,使用Element-ui进行页面布局。前端环境中使用Npm进行依赖管理,使用Babel进行代码转换,使用Webpack进行静态资源的打包,采用axios进行Ajax请求调用,使用了ECharts进行数据的图表展示。

1.2.功能简介

谷粒学院,是一个B2C模式的职业技能在线教育系统,分为前台用户系统和后台运营平台。
在这里插入图片描述

1.3.技术架构

在这里插入图片描述

二、Mybatis-Plus概述

2.1.简介

Mybatis-Plus官网:https://baomidou.com/

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

2.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 注入攻击

三、Mybatis-Plus入门

3.1.创建数据库

-- utf8mb4字符集和utf8mb4_unicode_ci排序规则被用于新创建的数据库
CREATE DATABASE mybatis_plus CHARACTER SET utf8 COLLATE utf8_unicode_ci;

在这里插入图片描述

3.2.创建 User 表

表结构

idnameageemail
1Jone18test1@baomidou.com
2Jack20test2@baomidou.com
3Tom28test3@baomidou.com
4Sandy21test4@baomidou.com
5Billie24test5@baomidou.com
-- 建表SQL语句
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(11) NULL DEFAULT NULL COMMENT '年龄',email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',PRIMARY KEY (id)
);-- 插入数据SQL语句
INSERT INTO user (id, name, age, email) VALUES(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),(5, 'Billie', 24, 'test5@baomidou.com');select * from user;

3.3.初始化一个SpringBoot工程

版本:2.2.1.RELEASE
在这里插入图片描述

3.4.在Pom文件中引入SpringBoot和Mybatis-Plus相关依赖

spring-boot-starter、spring-boot-starter-test
添加:mybatis-plus-boot-starter、MySQL、lombok
注意:引入 MyBatis-Plus 之后请不要再次引入 MyBatis 以及 MyBatis-Spring,以避免因版本差异导致的问题。

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.1.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.orange</groupId><artifactId>mybatis_plus_demo</artifactId><version>0.0.1-SNAPSHOT</version><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><!--mybatis-plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.2</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--lombok用来简化实体类--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

3.5.第一次使用lombok需要在IDEA中安装lombok插件

在这里插入图片描述

在这里插入图片描述

3.6.MySQL 数据库的相关配置

application.properties 配置文件中添加 MySQL 数据库的相关配置:

#mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.147.133:3306/mybatis_plus?characterEncoding=utf-8&&useSSL=false
spring.datasource.username=root
spring.datasource.password=Mysql.123456
-- 查看MySQL的版本mysql -VSELECT VERSION();

在这里插入图片描述

3.7.编写代码

3.7.1.主类:

在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹
注意:扫描的包名根据实际情况修改

@SpringBootApplication
@MapperScan("com.orange.mybatisplus.mapper")
public class MybatisPlusDemoApplication {public static void main(String[] args) {SpringApplication.run(MybatisPlusDemoApplication.class, args);}}

3.7.2.实体类:

创建包 entity 编写实体类 User.java

/*** Description: User实体类*/
@Data
public class User {private Long id;private String name;private Integer age;private String email;
}

查看编译结果
在这里插入图片描述

3.7.3.mapper:

创建包 mapper 编写Mapper 接口: UserMapper.java

@Repository
public interface UserMapper extends BaseMapper<User> {}

3.8.开始使用

3.8.1.查询所有用户,代码测试

@SpringBootTest
public class MybatisPlusDemoApplicationTests {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelectList() {System.out.println(("----- selectAll method test ------"));//UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper//所以不填写就是无任何条件List<User> users = userMapper.selectList(null);users.forEach(System.out::println);}}

3.8.2.UserMapper(加注解)

@Repository
public interface UserMapper extends BaseMapper<User> {
}

注意:

IDEA在 UserMapper 处报错,因为找不到注入的对象,因为类是动态创建的,但是程序可以正确的执行。

为了避免报错,可以在 dao 层 的接口上添加 @Repository 注解

3.8.3.运行结果

----- selectAll method test ------
User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)

3.9.配置日志

#查看sql输出日志
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
----- selectAll method test ------
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3e6534e7] was not registered for 
synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@118363130 wrapping com.mysql.cj.jdbc.ConnectionImpl@6ff415ad] 
will not be managed by Spring
==>  Preparing: SELECT id,name,age,email FROM user 
==> Parameters: 
<==    Columns: id, name, age, email
<==        Row: 1, Jone, 18, test1@baomidou.com
<==        Row: 2, Jack, 20, test2@baomidou.com
<==        Row: 3, Tom, 28, test3@baomidou.com
<==        Row: 4, Sandy, 21, test4@baomidou.com
<==        Row: 5, Billie, 24, test5@baomidou.com
<==      Total: 5
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3e6534e7]
User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)

四、Mybatis-Plus相关操作

4.1.插入操作【insert】

    //添加数据操作@Testpublic void addUser(){User user = new User();user.setName("libai");user.setAge(18);user.setEmail("123456@163.com");int result = userMapper.insert(user);System.out.println("insert:"+result); //影响的行数System.out.println(user); //id自动回填}

注意:数据库插入id值默认为:全局唯一id
在这里插入图片描述

4.2.主键生成策略

在这里插入图片描述

4.2.1.ID_WORKER

MyBatis-Plus默认的主键策略是:ID_WORKER 全局唯一ID
参考资料:分布式系统唯一ID生成方案汇总:https://www.cnblogs.com/haoxinyue/p/5208136.html

4.2.2.自增策略

  • 要想主键自增需要配置如下主键策略
    • 需要在创建数据表的时候设置主键自增
    • 实体字段中配置 @TableId(type = IdType.AUTO)
@TableId(type = IdType.AUTO)
private Long id;

要想影响所有实体的配置,可以设置全局主键配置

#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto

其它主键策略:分析 IdType 源码可知

public enum IdType {AUTO(0),//数据库ID自增NONE(1),//该类型为未设置主键类型INPUT(2),//用户输入ID 该类型可以通过自己注册自动填充插件进行填充/* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */ID_WORKER(3),//全局唯一ID (idWorker)UUID(4),//全局唯一ID (UUID)ID_WORKER_STR(5);//字符串全局唯一ID (idWorker 的字符串表示)private int key;private IdType(int key) {this.key = key;}public int getKey() {return this.key;}}

4.3.根据Id更新操作【update】

注意:update时生成的sql自动是动态sql:UPDATE user SET age=? WHERE id=?

    //修改操作@Testpublic void updateUserById() {User user = new User();user.setId(1L);user.setName("tiny");user.setAge(30);int row = userMapper.updateById(user);System.out.println(row);}

在这里插入图片描述
在这里插入图片描述

4.4.自动填充

项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间更新时间等。
我们可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作:

4.4.1.数据库表中添加自动填充字段

在User表中添加datetime类型的新的字段 create_timeupdate_time

-- 删除字段
ALTER TABLE user drop createTime,drop updateTime;
-- 删除单个字段 alter table 表名称 drop 字段;
-- 删除多个字段 alter table 表名称 drop 字段1,drop 字段2,drop 字段3;-- 添加字段
ALTER TABLE userADD COLUMN create_time datetime  COMMENT '创建时间',ADD COLUMN update_time datetime  COMMENT '更新时间';desc user;show create table user;

在这里插入图片描述

在这里插入图片描述

4.4.2.实体上添加注解

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {//@TableId(type = IdType.ID_WORKER) //mp自带策略,生成19位值,数字类型使用这种策略,比如long//@TableId(type = IdType.ID_WORKER_STR) //mp自带策略,生成19位值,字符串类型使用这种策略//主键自动增长策略//@TableId(type = IdType.AUTO)private Long id;private String name;private Integer age;private String email;//自动填充属性添加注解//注解填充字段 @TableField(.. fill = FieldFill.INSERT) 生成器策略部分也可以配置//create_time@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;//update_time//@TableField(fill = FieldFill.UPDATE)@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime updateTime;
}

4.4.3.测试添加数据

    //添加用户@Testpublic void addUserAuto() {User user = new User();user.setName("dufu");user.setAge(60);user.setEmail("123456@163.com");//手动设置时间值user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());int result = userMapper.insert(user);System.out.println("insert:" + result); //影响的行数System.out.println(user); //id自动回填}

4.4.4.测试结果

在这里插入图片描述
在这里插入图片描述

4.4.5.自动填充策略FieldFill

public enum FieldFill {/*** 默认不处理*/DEFAULT,/*** 插入填充字段*/INSERT,/*** 更新填充字段*/UPDATE,/*** 插入和更新填充字段*/INSERT_UPDATE;private FieldFill() {}
}

4.4.6.自定义实现类 MyMetaObjectHandler实现元对象处理器接口

注意:不要忘记添加 @Component 注解

/*** Description: 自定义实现类 MyMetaObjectHandler  自动填充功能*/
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {//使用mq实现添加操作,这个方法执行@Overridepublic void insertFill(MetaObject metaObject) {log.info("start insert fill ....");//根据名称设置属性值//this.setFieldValByName("createTime", LocalDateTime.now(), metaObject);// 也可以使用(3.3.0 该方法有bug)this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());// 起始版本 3.3.0(推荐使用)//this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class);// 起始版本 3.3.3(推荐)this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());}//使用mq实现修改操作,这个方法执行@Overridepublic void updateFill(MetaObject metaObject) {log.info("start update fill ....");this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());}
}

4.4.7.测试添加数据

    //添加用户@Testpublic void addUserAuto() {User user = new User();user.setName("baijuyi");user.setAge(110);user.setEmail("111111@163.com");int result = userMapper.insert(user);System.out.println("insert:" + result); //影响的行数System.out.println(user); //id自动回填}

4.4.8.测试结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.5.乐观锁

主要适用场景:当要更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新
乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败

4.5.1.表中添加version字段,作为乐观锁版本号

-- 添加字段
ALTER TABLE user ADD COLUMN version INT  COMMENT '版本号';desc user;

在这里插入图片描述

4.5.2.实体类添加version属性

并添加 @Version 注解

    @Version@TableField(fill = FieldFill.INSERT)private Integer version;//版本号

4.5.3.元对象处理器接口添加version的insert默认值

    @Overridepublic void insertFill(MetaObject metaObject) {......this.strictInsertFill(metaObject, "version", Integer.class, 1);}

特别说明:

  • 支持的数据类型只有 int,Integer,long,Long,Date,Timestamp,LocalDateTime
  • 整数类型下 newVersion = oldVersion + 1
  • newVersion 会回写到 entity
  • 仅支持 updateById(id)update(entity, wrapper) 方法
  • update(entity, wrapper) 方法下, wrapper 不能复用!!!

4.5.4.创建配置类MybatisPlusConfig 并注册 Bean

/*** Description: Mybatis-plus配置类*/
@Configuration
@MapperScan("com.orange.mybatisplus.mapper")
public class MybatisPlusConfig {/*** 乐观锁插件*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;}
}

4.5.5.测试乐观锁可以修改成功

测试后分析打印的sql语句,将version的数值进行了加1操作

    //测试 乐观锁插件 添加数据@Testpublic void testOptimisticLockerAddUser() {User user = new User();user.setName("wangwu");user.setAge(100);user.setEmail("100000@163.com");int result = userMapper.insert(user);System.out.println("insert:" + result); //影响的行数System.out.println(user); //id自动回填}//测试 乐观锁插件@Testpublic void testOptimisticLocker() {//查询User user = userMapper.selectById(1765668893893959681L);System.out.println(user);//修改数据user.setName("lisi");user.setEmail("lisi@qq.com");//执行更新userMapper.updateById(user);System.out.println(user);}

在这里插入图片描述
在这里插入图片描述

4.5.6.测试乐观锁修改失败

    //测试乐观锁插件 失败@Testpublic void testOptimisticLockerFail() {//查询User user = userMapper.selectById(1765668893893959681L);System.out.println(user);//修改数据user.setName("lisi1");user.setEmail("lisi@qq.com1");//模拟取出数据后,数据库中version实际数据比取出的值大,即已被其它线程修改并更新了versionuser.setVersion(user.getVersion() - 1);//执行更新userMapper.updateById(user);System.out.println(user);}

在这里插入图片描述

4.6.select【查询】

4.6.1.根据id查询记录

    //根据id查询记录@Testpublic void testSelectById() {User user = userMapper.selectById(1L);System.out.println("user = " + user);}

在这里插入图片描述

4.6.2.通过多个id批量查询

    //通过多个id批量查询//完成了动态sql的foreach的功能@Testpublic void testSelectBatchIds() {List<User> userList = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));userList.forEach(System.out::println);}

在这里插入图片描述

4.6.3.简单的条件查询

    //简单的条件查询//通过map封装查询条件@Testpublic void testSelectByMap() {HashMap<String, Object> hashMap = new HashMap<>();//注意:map中的key对应的是数据库中的列名。//例如数据库user_id,实体类是userId,这时map的key需要填写user_idhashMap.put("name", "lisi");hashMap.put("age", 100);List<User> userList = userMapper.selectByMap(hashMap);userList.forEach(System.out::println);}

在这里插入图片描述

4.6.4.分页

MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能

4.6.4.1.创建配置类-添加分页插件
@Configuration
@MapperScan("com.orange.mybatisplus.mapper")
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//添加分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加//interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType//添加乐观锁插件interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;}
}
4.6.4.2.测试selectPage分页

测试:最终通过page对象获取相关数据

    //分页查询@Testpublic void testSelectPage() {//创建Page对象//传入两个参数:当前页 和 每页显示记录数//Page<User> page = new Page<>(1, 3);Page<User> page = new Page<>(2, 3);//调用mp分页查询的方法//调用mq分页查询过程中,底层封装//把分页所有数据封装到page对象里面userMapper.selectPage(page, null);//通过page对象获取分页数据page.getRecords().forEach(System.out::println);System.out.println("当前页: " + page.getCurrent());System.out.println("每页数据list集合: " + page.getRecords());System.out.println("每页显示记录数: " + page.getSize());System.out.println("总页数: " + page.getPages());System.out.println("总记录数: " + page.getTotal());System.out.println("是否有下一页: " + page.hasNext());System.out.println("是否有上一页: " + page.hasPrevious());}


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.6.4.3.测试selectMapsPage分页:结果集是Map
    //测试selectMapsPage分页:结果集是Map@Testpublic void testSelectMapsPage() {//创建Page对象//传入两个参数:当前页 和 每页显示记录数Page page = new Page<>(2, 3);//调用mp查询的方法IPage<Map<String, Object>> mapsPage = userMapper.selectMapsPage(page, null);//注意:此行必须使用 mapIPage 获取记录列表,否则会有数据类型转换错误mapsPage.getRecords().forEach(System.out::println);System.out.println("当前页: " + page.getCurrent());System.out.println("每页数据list集合: " + page.getRecords());System.out.println("每页显示记录数: " + page.getSize());System.out.println("总页数: " + page.getPages());System.out.println("总记录数: " + page.getTotal());System.out.println("是否有下一页: " + page.hasNext());System.out.println("是否有上一页: " + page.hasPrevious());}

在这里插入图片描述
在这里插入图片描述

4.7.delete【物理删除】

4.7.1.根据id删除记录

    //根据id删除记录@Testpublic void testDeleteById() {int result = userMapper.deleteById(1L);System.out.println(result);}

在这里插入图片描述
在这里插入图片描述

4.7.2.批量删除

    //批量删除@Testpublic void testDeleteBatchIds() {int result = userMapper.deleteBatchIds(Arrays.asList(2, 3, 4));System.out.println(result);}

在这里插入图片描述
在这里插入图片描述

4.7.3.简单的条件查询删除

    //简单的条件查询删除@Testpublic void testDeleteByMap() {HashMap<String, Object> map = new HashMap<>();map.put("name", "baijuyi");map.put("age", 110);int result = userMapper.deleteByMap(map);System.out.println(result);}

在这里插入图片描述
在这里插入图片描述

4.8.【逻辑删除】

  • 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据
  • 逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录

4.8.1.数据库中添加 deleted字段

-- 添加字段
ALTER TABLE user ADD COLUMN deleted boolean default 0 COMMENT '被删除状态';desc user;

在这里插入图片描述
在这里插入图片描述

4.8.2.实体类添加deleted 字段并加上 @TableLogic 逻辑删除注解

并加上 @TableLogic 注解 和 @TableField(fill = FieldFill.INSERT) 注解

	//实体类字段上加上@TableLogic注解@TableLogic@TableField(fill = FieldFill.INSERT)private Integer deleted;

4.8.3.元对象处理器接口添加deleted的insert默认值

    @Overridepublic void insertFill(MetaObject metaObject) {......this.strictInsertFill(metaObject, "deleted", Integer.class, 0);}

4.8.4.application.properties 加入配置

此为默认值,如果你的默认值和mp默认的一样,该配置可无

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

4.8.5.测试逻辑删除

  • 测试后发现,数据并没有被删除,deleted字段的值由0变成了1
  • 测试后分析打印的sql语句,是一条update
  • 注意:被删除数据的deleted 字段的值必须是 0,才能被选取出来执行逻辑删除的操作
    //测试 逻辑删除@Testpublic void testLogicDelete() {int result = userMapper.deleteById(5L);System.out.println(result);}

在这里插入图片描述
在这里插入图片描述

4.8.6.测试逻辑删除后的查询

MyBatis Plus中查询操作也会自动添加逻辑删除字段的判断

    //测试 逻辑删除后的查询:不包括被逻辑删除的记录@Testpublic void testLogicDeleteSelect() {User user = new User();List<User> users = userMapper.selectList(null);users.forEach(System.out::println);}
测试后分析打印的sql语句,包含 WHERE deleted=0 
SELECT id,name,age,email,create_time,update_time,version,deleted FROM user WHERE deleted=0

在这里插入图片描述

五、性能分析

性能分析拦截器,用于输出每条 SQL 语句及其执行时间
SQL 性能执行分析,开发环境使用,超过指定时间,停止运行。有助于发现问题

5.1.配置插件

5.1.1.参数说明

  • 参数:maxTime: SQL 执行最大时长,超过自动停止运行,有助于发现问题。
  • 参数:format: SQL是否格式化,默认false。

5.1.2.在 MybatisPlusConfig 中配置

mybatis-plus中3.2.0 版本之后把PerformanceInterceptor功能被废除

        <!--mybatis-plus 3.4.2改为3.0.5测试性能 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.0.5</version></dependency>
/*** Description: Mybatis-plus配置类*/
@Configuration
@MapperScan("com.orange.mybatisplus.mapper")
public class MybatisPlusConfig {/*@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//添加分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加//interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType//添加乐观锁插件interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;}*///乐观锁插件@Beanpublic OptimisticLockerInterceptor optimisticLockerInterceptor() {return new OptimisticLockerInterceptor();}/*** 分页插件*/@Beanpublic PaginationInterceptor paginationInterceptor() {return new PaginationInterceptor();}//逻辑删除插件@Beanpublic ISqlInjector sqlInjector() {return new LogicSqlInjector();}/*** SQL 执行性能分析插件* 开发环境使用,线上不推荐。 maxTime 指的是 sql 最大执行时长** 三种环境*      * dev:开发环境*      * test:测试环境*      * prod:生产环境*/@Bean@Profile({"dev","test"})// 设置 dev test 环境开启public PerformanceInterceptor performanceInterceptor() {PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();performanceInterceptor.setMaxTime(500);//ms,超过此处设置的ms则sql不执行performanceInterceptor.setFormat(true);return performanceInterceptor;}
}

5.1.3.自定义实现类 MyMetaObjectHandler

/*** Description: 自定义实现类 MyMetaObjectHandler  自动填充功能*/
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {//使用mq实现添加操作,这个方法执行@Overridepublic void insertFill(MetaObject metaObject) {log.info("start insert fill ....");//根据名称设置属性值//this.setFieldValByName("createTime", LocalDateTime.now(), metaObject);// 也可以使用(3.3.0 该方法有bug)/*this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());// 起始版本 3.3.0(推荐使用)//this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class);// 起始版本 3.3.3(推荐)this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());this.strictInsertFill(metaObject, "version", Integer.class, 1);this.strictInsertFill(metaObject, "deleted", Integer.class, 0);*/this.setFieldValByName("createTime", LocalDateTime.now(), metaObject);this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);this.setFieldValByName("version", 1, metaObject);this.setFieldValByName("deleted", 0, metaObject);}//使用mq实现修改操作,这个方法执行@Overridepublic void updateFill(MetaObject metaObject) {log.info("start update fill ....");//this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);}
}

5.1.4.Spring Boot 中设置dev环境

#环境设置:dev、test、prod
spring.profiles.active=dev

可以针对各环境新建不同的配置文件application-dev.propertiesapplication-test.propertiesapplication-prod.properties
也可以自定义环境名称:如test1、test2

5.2.测试

5.2.1.常规测试

/*** Description:测试性能*/
@SpringBootTest
public class Perform {@Autowiredprivate UserMapper userMapper;//测试 性能分析插件@Testpublic void testPerformance() {User user = new User();user.setName("我是Helen");user.setEmail("helen@sina.com");user.setAge(18);userMapper.insert(user);}
}

输出:
在这里插入图片描述
在这里插入图片描述

5.2.2.将maxTime 改小之后再次进行测试

performanceInterceptor.setMaxTime(1);//ms,超过此处设置的ms不执行

如果执行时间过长,则抛出异常:The SQL execution time is too large,
输出:
在这里插入图片描述
在这里插入图片描述

六、条件构造器 Wrapper

复杂条件查询,需要使用条件构造器 Wrapper

在这里插入图片描述

在这里插入图片描述

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

endl 小技巧:护眼模式:CAE6CA、C7EDCC

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/728376.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

融资项目——OpenFeign的降级与熔断

当一个微服务调用其他微服务时&#xff0c;如果被调用的微服务因各种原因无法在规定时间内提供服务&#xff0c;则可以直接使用本地的服务作为备选&#xff0c;即进行降级熔断。 如之前所提到的微服务为例&#xff1a; 如果希望实现降级熔断&#xff0c;可以在本地创建一个实现…

AI改变游戏规则:内容创作的新时代!

AI技术&#xff0c;尤其是人工智能&#xff08;AI&#xff09;在内容创作领域的应用&#xff0c;正开启了一个全新的时代。这一时代的核心在于利用AI的能力&#xff0c;不仅提高内容创作的效率&#xff0c;还能引入前所未有的创新元素&#xff0c;从而彻底改变游戏规则。 AI在…

OpenCV与AI深度学习 | 基于OpenCV实现模糊检测 / 自动对焦

本文来源公众号“OpenCV与AI深度学习”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;基于OpenCV实现模糊检测 / 自动对焦 导 读 本文主要介绍使用OpenCV实现图像模糊检测/相机自动对焦功能。 前 言 为了检测图片是否对焦&…

coqui-ai/TTS 案例model文件

GitHub - coqui-ai/TTS: &#x1f438;&#x1f4ac; - a deep learning toolkit for Text-to-Speech, battle-tested in research and production Coqui AI的TTS是一款开源深度学习文本转语音工具&#xff0c;以高质量、多语言合成著称。它提供超过1100种语言的预训练模型库&…

C#,哈夫曼编码(Huffman Code)压缩(Compress )与解压缩(Decompress)算法与源代码

David A. Huffman 1 哈夫曼编码简史&#xff08;Huffman code&#xff09; 1951年&#xff0c;哈夫曼和他在MIT信息论的同学需要选择是完成学期报告还是期末考试。导师Robert M. Fano给他们的学期报告的题目是&#xff0c;寻找最有效的二进制编码。由于无法证明哪个已有编码是…

java编程的简化表达方法——Lambda表达式及方法引用概述

前言&#xff1a; 学到简化写法了&#xff0c;感觉需要对代码非常熟悉才能用得好&#xff0c;整理下写法。打好基础&#xff0c;daydayup! Lambda表达式 Lambda表达式是JDK8开始新增得一种语法形式&#xff1b;作用&#xff1a;用于简化匿名内部类的代码写法。 Lambda表达式的格…

蓝桥杯嵌入式模板构建——RCT时钟

在CubeMX里的RTC模块启用RTC时钟和日历功能 输入到RTC的时钟要配置成1HZ,这样的话RTC每经过1s走时一次 由于RTC时钟默认配置为32Khz 所以我们需要将异步分频值与同步分频值的乘积调整为32K分频即可一秒走时一次 频率&#xff1a;32000hz / 32000hz 1hz 必须是31和999&#…

阿珊详解Vue路由的两种模式:hash模式与history模式

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

计算机网络面经-HTTPS加密过程

前言 在上篇文章HTTPS详解一中&#xff0c;我已经为大家介绍了 HTTPS 的详细原理和通信流程&#xff0c;但总感觉少了点什么&#xff0c;应该是少了对安全层的针对性介绍&#xff0c;那么这篇文章就算是对HTTPS 详解一的补充吧。还记得这张图吧。 HTTPS 和 HTTP的区别 显然&am…

idea Gradle 控制台中文乱码

如下图所示&#xff0c;idea 中的 Gradle 控制台中文乱码&#xff1a; 解决方法&#xff0c;如下图所示&#xff1a; 注意&#xff1a;如果你的 idea 使用 crack 等方式破解了&#xff0c;那么你可能需要在文件 crack-2023\jetbra\vmoptions\idea.vmoptions 中进行配置&#xf…

Java引用传递及基本应用

在 Java 中&#xff0c;传递参数的方式主要有两种&#xff1a;值传递&#xff08;传递的是对象的引用值&#xff09;和引用传递。本教程将重点介绍 Java 中的引用传递以及其基本应用。 1. 引用传递概念 在 Java 中&#xff0c;所有的方法参数都是通过值传递的。对于对象类型的…

MAC 的vscode菜单栏怎么调?

我去&#xff0c;这个bug找到了半天&#xff0c;终于找到正解了&#xff0c;仅记录&#xff0c;为广大和我一样不熟悉mac的兄弟们避坑。 正解&#xff1a;mac的vscode的菜单栏在屏幕最顶上&#xff0c;不用调出来&#xff0c;人家一直都有。

Redis集群(哨兵集群)

一.Sentinel作用和原理: 1.作用 监控:Sentinel会不断监控master和slave是否按预期工作. 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也会以新的master为主。 通知&#xff1a;Sentinel充当redis客户端的服务发现来源,当集群发生故障…

SAP MM学习笔记44 - 特殊调达流程 - Blanket购买发注(汇总采购)

上一章学习了 支付计划&#xff0c;本章继续学习 Blanket购买发注&#xff08;汇总采购&#xff09;。 SAP MM学习笔记43 - 特殊调达流程 - 支付计划-CSDN博客 1&#xff0c;Blanket购买发注 概要 其实就是订好一个大致数额&#xff0c;然后让随便买&#xff0c;只要不超这个…

一篇文章教会你Python+selenium自动化生成测试报告

前言 批量执行完用例后&#xff0c;生成的测试报告是文本形式的&#xff0c;不够直观&#xff0c;为了更好的展示测试报告&#xff0c;最好是生成HTML格式的。 unittest里面是不能生成html格式报告的&#xff0c;需要导入一个第三方的模块&#xff1a;HTMLTestRunner 一、导…

Vue2+3

vue相关介绍 Vue的两种使用方式&#xff1a; 1、vue核心包开发 场景&#xff1a;局部模块改造 2、vue核心包&vue插件工程化开发 场景&#xff1a;整站开发 概念&#xff1a;vue是用于构建用户界面的渐进式框架 创建vue实例 创建Vue实例&#xff0c;初始化渲染步骤&am…

基于C/S架构的在线阅读器

项目简介 本项目实现了用户的基本阅读功能。项目内容涉及到IO&#xff0c;网络编程&#xff0c;C&#xff0c;QT等知识点。本次项目服务器搭建在ubuntu上&#xff0c;客户端ui在QT中实现&#xff0c;客户端和服务器使用套接字通信。 一、基本功能展示 &#xff08;1&#xff…

计算阶梯数 Python

题目描述 爱因斯坦曾出过这样一道有趣的数学题&#xff1a; 有一个长阶梯&#xff0c; 若每步上2阶&#xff0c;最后剩1阶&#xff1b; 若每步上3阶&#xff0c;最后剩2阶&#xff1b; 若每步上5阶&#xff0c;最后剩4阶&#xff1b; 若每步上6阶&#xff0c;最后剩5阶&#xf…

20240304-使用VS2022编译blender3.6.2源代码

20240304-使用VS2022编译blender3.6.2源代码 一、软件环境 Win10 x64 22h2 JuneVS2022 v17.9.0CMake v3.24.4SVN v1.14.3GIT v2.29.2标签&#xff1a;win10 22h2 vs2022 blender 63335分栏&#xff1a;C 二、硬件环境 Win10 x64的PC台式机 三、获取源码 方法一 网盘下载…

【黑马程序员】C++项目之机房预约管理系统实战

文章目录 需求系统简介身份介绍机房介绍申请简介系统具体需求 实现菜单与退出功能实现功能测试 创建身份类创建角色基类创建学生类创建教师类创建管理员类 登录模块功能描述登录函数封装各个校色具体登录验证管理员操作界面调用流程 管理员模块构造函数实现管理员子菜单显示添加…