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

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

  • 一、项目概述
    • 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.hqwc.cn/news/519308.html

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

相关文章

图机器学习(1)--导论

0 引入 为什么是图&#xff1f;图是描述关联数据的通用语言。 前期的研究&#xff1a;节点之间独立同分布&#xff0c;没有关系。 图&#xff1a;节点之间有关联关系。 0.1 图数据举例 0.2 问题描述 黏菌按照人类规划的铁路网进行生长。 复杂域具有丰富的关系结构&#xf…

开放式高实时高性能PLC控制器解决方案-基于米尔电子STM32MP135

前言 随着工业数字化进程加速与IT/OT深入融合&#xff0c;不断增加的OT核心数据已经逐步成为工业自动化行业的核心资产&#xff0c;而OT层数据具备高实时、高精度、冗余度高、数据量大等等特点&#xff0c;如何获取更加精准的OT数据对数字化进程起到至关重要的作用&#xff0c;…

虽说主业搞前端,看到如此漂亮的网页UI,也是挪不开眼呀。

漂亮的网页UI能够吸引人的眼球&#xff0c;给人留下深刻的印象。作为前端开发人员&#xff0c;可以通过不断学习和掌握设计技巧和工具&#xff0c;提升自己的UI设计能力&#xff0c;为用户提供更好的视觉体验。 以下是一些提升网页UI设计能力的建议&#xff1a; 学习设计基础知…

MySQL基础(未完待续...)

数据库基础 MySQL概述 数据库相关概念 名称作用简称数据库存储数据的仓库&#xff0c;数据是有组织的进行存储DataBase&#xff08;DB&#xff09;数据库管理系统操纵和管理数据库的大型软件DataBase Management System (DBMS)SQL操作关系型数据库的编程语言&#xff0c;定义…

个人项目介绍4:三维园区篇

个人项目介绍: 地图铁路线路篇 地球卫星篇 火车站篇 三维园区篇 项目需求&#xff1a; 1.按比例全景显示三维园区 2.精确显示园区内设备设施 3.实时显示设备报警信息 4.显示园区内摄像监控设备&#xff0c;并可点击显示监控视频流 5.显示园区内的重大危险源和风险分布 …

算法题 — 三个数的最大乘机

三个数的最大乘机 整型数组 nums&#xff0c;在数组中找出由三个数字组成的最大乘机&#xff0c;并输出这个乘积。&#xff08;乘积不会越界&#xff09; 重点考察&#xff1a;线性扫描 排序法&#xff1a; public static void main(String[] args) {System.out.println(so…

SpringMVC实用技术

1.校验框架 1.表单校验框架入门 表单校验的重要性 数据可以随意输入&#xff0c;导致错误的结果。表单校验保障了数据有效性、安全性 表单校验分类 校验位置&#xff1a; 客户端校验 服务端校验 校验内容与对应方式&#xff1a; 格式校验 客户端&#xff1a;使用Js技术…

MySQL学习Day24—数据库的设计规范

一、数据库设计的重要性: 1.糟糕的数据库设计产生的问题: (1)数据冗余、信息重复、存储空间浪费 (2)数据更新、插入、删除的异常 (3)无法正确表示信息 (4)丢失有效信息 (5)程序性能差 2.良好的数据库设计有以下优点: (1)节省数据的存储空间 (2)能够保证数据的完整性 …

多层菜单的实现方案(含HierarchicalDataTemplate使用)

1、递归 下面是Winform的递归添加菜单栏数据&#xff0c;数据设置好父子id方便递归使用 在TreeView的控件窗口加载时&#xff0c;调用递归加载菜单 private void LoadTvMenu(){this.nodeList objService.GetAllMenu(); // 通过Service得到全部数据// 创建一个根节点this.t…

事务控制失效的八种常见原因

一、非public修饰的方法 Transactional注解只能在在public修饰的方法下使用。 /*** 私有方法上的注解&#xff0c;不生效&#xff08;因私有方法Spring扫描不到该方法&#xff0c;所以无法生成代理&#xff09;*/ Transactional private boolean test() {//test code } 二、…

【Linux】权限管理(文件的访问者、类型和访问权限,chmod、chown、chgrp、umask,粘滞位)

目录 00.前言 01.文件访问者的分类 02.文件类型和访问权限 文件类型&#xff1a; 文件基本权限&#xff1a; 03.文件权限值的表示方法 04.访问权限的设置 &#xff08;1&#xff09;chmod &#xff08;2&#xff09;chown &#xff08;3&#xff09;chgrp &#xff0…

OpenHarmony教程指南—Ability的启动模式

介绍 本示例展示了在一个Stage模型中&#xff0c;实现standard、singleton、specified多种模式场景。 本实例参考开发指南 。 本实例需要使用aa工具 查看应用Ability 模式信息。 效果预览 使用说明 1、standard模式&#xff1a; 1&#xff09;进入首页&#xff0c;点击番茄…