0
点赞
收藏
分享

微信扫一扫

mybatis-plus的使用

纽二 2022-02-19 阅读 178

文章目录


前言

本文采用Springboot集成mybatis-plus,记录了集成的全部的详细操作。希望大家看到之后一起交流学习


一、mybatis-plus是什么?

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

愿景:

我们的愿景是成为 MyBatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率翻倍。

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑

  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作

  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求

  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错

  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题

  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作

  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )

  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用

  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询

  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库

  • 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询

  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

     

    官网:MyBatis-Plus

    注:

    ps:切记不可再在pom.xml文件中引入mybatis与mybatis-spring的maven依赖,这一点,mybatis-plus的官方文档中已经说明的很清楚了

二、使用步骤

1.快速入门

mybatis-plus 快速使用

  1. 导入相关依赖

<!--mysql驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<!-- mybatis-plus不需要再额外引入mybatis了-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.2</version>
</dependency>
<!--lombok-->
<dependency>
     <groupId>org.projectlombok</groupId>
     <artifactId>lombok</artifactId>
     <version>1.18.18</version>
</dependency>

2.创建数据表并编写Entity实体(刚入门测试,后续代码生成器可以全部生成controller、service、mapper、实体等都可以生成)

CREATE TABLE it_employee (
  id INT(11) PRIMARY KEY auto_increment,
	emp_name VARCHAR(50),
  emp_email VARCHAR(50),
  gender CHAR(1),
  age INT(10)
);

INSERT INTO it_employee VALUES (NULL,'张三','zhangsan@163.com','0',18);
INSERT INTO it_employee VALUES (NULL,'李四','lisi@163.com','1',21);
INSERT INTO it_employee VALUES (NULL,'王五','wangwu@163.com','1',19);
INSERT INTO it_employee VALUES (NULL,'赵六','zhaoliu@163.com','0',17);

实体采用的lombok

import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.Date;

 
/* 
 * MybatisPlus会默认使用实体类的类名到数据中找对应的表. 
 * 所以表名和实体类名不一致时需要使用@TableName
 */ 

@Component
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "it_employee")
public class ItEmployee {
 
/* 
 * @TableId: 
 * value: 指定表中的主键列的列名, 如果实体属性名与列名一致,可以省略不指定.
 * type: 指定主键策略. 
 */ 
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    @TableField(value = "emp_name")
    private String empName;
    @TableField(value = "emp_email")
    private String empEmail;
    private String gender;
    private Integer age;
}


上面实体类中使用到了常用的注解,那我们先来介绍一下常用的注解

mybatis-plus中常用的注解

@TableName:对数据表名注解 

@TableId:表主键标识 

@TableId(value = "id", type = IdType.AUTO):自增 

@TableId(value = "id", type = IdType.ID_WORKER_STR):分布式全局唯一ID字符串类型 

@TableId(value = "id", type = IdType.INPUT):自行输入 

 @TableId(value = "id", type = IdType.ID_WORKER):分布式全局唯一ID 长整型类型 

 @TableId(value = "id", type = IdType.UUID):32位UUID字符串 

 @TableId(value = "id", type = IdType.NONE):无状态 

 @TableField:表字段标识 

 @TableField(exist = false):表示该属性不为数据库表字段,但又是必须使用的。 

 @TableField(exist = true):表示该属性为数据库表字段。 

 @TableField(condition = SqlCondition.LIKE):表示该属性可以模糊搜索。 

 @TableField(fill = FieldFill.INSERT):注解填充字段 ,生成器策略部分也可以配置! 

 @FieldStrategy: 

 @FieldFill 

 @Version:乐观锁注解、标记 

 @EnumValue:通枚举类注解 

 @TableLogic:表字段逻辑处理注解(逻辑删除) 

 @SqlParser:租户注解 

 @KeySequence:序列主键策略

常用的就三个:

@TableName

@TableId

@TableField

查看更多注解以及详解,请移步至官网:

https://mybatis.plus/guide/annotation.html 

3.配置yml基本的数据库连接信息以及数据源设置,这里数据源采用的是druid

# 数据源
spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/stupubdemo?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=10
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
server:
  port: 80

  1. 新建mappe进行操作

@Mapper
public interface ItEmployeedao extends BaseMapper<ItEmployee> {
}

BaseMapper<T>的介绍:

只需要继承BaseMapper就好无需编写其他方法,在使用Mybatis-Plus是,核心操作类是BaseMapper接口,其最终也是利用的Mybatis接口编程的实现机制,其默认提供

了一系列的增删改查的基础方法,并且开发人员对于这些基础操作不需要写SQL进行处理操作(Mybatis提供的机制就是 需要开发人员在mapper.xml中提供sql语句),那样我们可以猜测肯定是Mybatis-Plus完成了BaseMapper接口提供的 方法的SQL语句的生成操作

BaseMapper中提供的方法:

import com.baomidou.mybatisplus.core.conditions.Wrapper; 
import com.baomidou.mybatisplus.core.metadata.IPage; 
import com.baomidou.mybatisplus.core.toolkit.Constants; 
import org.apache.ibatis.annotations.Param; 
import java.io.Serializable; 
import java.util.Collection; 
import java.util.List; 
import java.util.Map; 
 /** 
 * Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能 
 * <p>这个 Mapper 支持 id 泛型</p> 
 * 
 * @author hubin 
 * @since 2016‐01‐23 
 */ 
 public interface BaseMapper<T> extends Mapper<T> { 

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

/** 
* 根据 ID 删除 
* 
* @param id 主键ID 
*/ 
int deleteById(Serializable id); 

/** 
* 根据 columnMap 条件,删除记录 
* 
* @param columnMap 表字段 map 对象 
*/ 
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap); 

/** 
* 根据 entity 条件,删除记录 
* 
* @param wrapper 实体对象封装操作类(可以为 null) 
*/63 int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper); 

/** 
* 删除(根据ID 批量删除) 
* 
* @param idList 主键ID列表(不能为 null 以及 empty) 
*/ 
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); 

/** 
* 根据 ID 修改 
* 
* @param entity 实体对象 
*/ 
int updateById(@Param(Constants.ENTITY) T entity); 

/** 
* 根据 whereEntity 条件,更新记录 
* 
* @param entity 实体对象 (set 条件值,可以为 null) 
* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句) 
*/ 
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper); 

/** 
* 根据 ID 查询 
* 
* @param id 主键ID 
*/ 
T selectById(Serializable id); 

/** 
* 查询(根据ID 批量查询) 
* 
* @param idList 主键ID列表(不能为 null 以及 empty) 
*/ 
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); 
 
 /** 
 * 查询(根据 columnMap 条件) 
 * 
 * @param columnMap 表字段 map 对象 
 */ 
 List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap); 
 
 /** 
 * 根据 entity 条件,查询一条记录 
 * 
 * @param queryWrapper 实体对象封装操作类(可以为 null) 
 */ 
 T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); 
 
 /** 
 * 根据 Wrapper 条件,查询总记录数117 * 
 * @param queryWrapper 实体对象封装操作类(可以为 null) 
 */ 
 Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); 
 
 /** 
 * 根据 entity 条件,查询全部记录 
 * 
 * @param queryWrapper 实体对象封装操作类(可以为 null) 
 */ 
 List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); 
 
 /** 
 * 根据 Wrapper 条件,查询全部记录 
 * 
 * @param queryWrapper 实体对象封装操作类(可以为 null) 
 */ 
 List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); 
 
 /** 
 * 根据 Wrapper 条件,查询全部记录 
 * <p>注意: 只返回第一个字段的值</p> 
 * 
 * @param queryWrapper 实体对象封装操作类(可以为 null) 
 */ 
 List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); 
 
 /** 
 * 根据 entity 条件,查询全部记录(并翻页) 
 * 
 * @param page 分页查询条件(可以为 RowBounds.DEFAULT) 
 * @param queryWrapper 实体对象封装操作类(可以为 null) 
 */ 
 <E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); 
 
 /** 
 * 根据 Wrapper 条件,查询全部记录(并翻页) 
 * 
 * @param page 分页查询条件 
 * @param queryWrapper 实体对象封装操作类 
 */ 
 <E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); 
 }

  1. 测试类编写CRUD代码

@Autowired
ItEmployeedao etEmployeedao;

/**
 * 按id查询
 */
@Test
void selectids(){
    ItEmployee itEmployee = new ItEmployee();
    itEmployee.setId(1);
    System.out.println(etEmployeedao.getByIiEmployees(itEmployee));
}

/**
 * 按id批量查询
 */
@Test
void selectidLists(){
    ArrayList<Integer> integers = new ArrayList<>();
    integers.add(1);
    integers.add(2);
    integers.add(3);
    System.out.println(etEmployeedao.getByIiEmployeesList(integers));
}
/**
 * 按多个参数查询map
 */
@Test
void selectidMaps(){
    HashMap<String, Object> map = new HashMap<>();
    map.put("id","1");
    map.put("age","18");
    System.out.println(etEmployeedao.getByIiEmployeesMap(map));
}
/**
 * 新增
 */
@Test
void  insert(){
    ItEmployee itEmployee = new ItEmployee();
    itEmployee.setAge(12);
    itEmployee.setEmpEmail("123@163.com");
    itEmployee.setEmpName("张三丰");
    itEmployee.setGender("0");
    int insert = etEmployeedao.insert(itEmployee);
    if (insert>0){
        System.out.println("新增成功!");
    }
}

/**
 * 编辑
 */
@Test
void  update(){
    ItEmployee itEmployee = new ItEmployee();
    itEmployee.setId(10);
    itEmployee.setAge(10);
    itEmployee.setEmpEmail("123456@163.com");
    itEmployee.setEmpName("张丰三");
    itEmployee.setGender("0");
    int insert = etEmployeedao.update(itEmployee);
    if (insert>0){
        System.out.println("修改成功!");
    }
}

/**
 * 删除
 */
@Test
void  del(){
    ItEmployee itEmployee = new ItEmployee();
    itEmployee.setId(7);
    int insert = etEmployeedao.del(itEmployee);
    if (insert>0){
        System.out.println("删除成功!");
    }
}

以上就是快速使用,基本操作都可以满足了,而且带条件的一些sql等都正好,上面是使用的mapper层直接使用,但是我们在实际开发中一般都会使用service,那么service层代码来了

2.复杂场景的使用

实现带service层的dai复杂条件的各种操作

  1. 以上快速使用的基础上,新建EmployeeService

import com.baomidou.mybatisplus.extension.service.IService;
import com.wq.mybatisplusdemo.demo.entity.ItEmployee;

public interface EmployeeService  extends IService<ItEmployee> {

}

新建EmployeeServiceimpl

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wq.mybatisplusdemo.demo.dao.ItEmployeedao;
import com.wq.mybatisplusdemo.demo.entity.ItEmployee;
import com.wq.mybatisplusdemo.demo.service.EmployeeService;
import org.springframework.stereotype.Service;

/***
 * service 实现类继承map提供通用的service基类
 */
@Service
public class EmployeeServiceimpl extends ServiceImpl<ItEmployeedao, ItEmployee> implements EmployeeService {
}

就这么简单,service层就这样就行了,里面也有许多的方法直接使用

就可以准备测试了,但是在测试之前不得不提的条件构造器---Wrapper

wrapper及其子类介绍

  1. Wrapper :条件构造抽象类,最顶端父类,抽象类中提供3个方法以及其他方法

(2)AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件,QueryWrapper(LambdaQueryWrapper) 和

UpdateWrapper(LambdaUpdateWrapper) 的父类用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where

条件

(3)AbstractWrapper比较重要,里面的方法需要重点学习.

该抽象类提供的重要方法如下:(3)AbstractLambdaWrapper : Lambda 语法使用 Wrapper统一处理解析 lambda 获取 column。

(4)LambdaQueryWrapper :看名称也能明白就是用于Lambda语法使用的查询Wrapper

(5)LambdaUpdateWrapper : Lambda 更新封装Wrapper

(6)QueryWrapper : Entity 对象封装操作类,不是用lambda语法,自身的内部属性 entity 也用于生成 where 条件

该类的重要方法:

select方法

1 select(String... sqlSelect)

2 select(Predicate<TableFieldInfo> predicate)

3 select(Class<T> entityClass, Predicate<TableFieldInfo> predicate)

4 /*

5 例: select("id", "name", "age")

6 例: select(i ‐> i.getProperty().startsWith("test"))

7 */

(7)UpdateWrapper : Update 条件封装,用于Entity对象更新操作.

该类主要有以下三个重要的方法:

set方法1 set(String column, Object val)

2 set(boolean condition, String column, Object val)

3 /*

4 SQL SET 字段

5 例: set("name", "老李头")

6 例: set("name", "")‐‐‐>数据库字段值变为空字符串

7 例: set("name", null)‐‐‐>数据库字段值变为null

8 说明:boolean condition为控制该字段是否拼接到最终的sql语句中

9 */

setSql方法

1 setSql(String sql)

2 /*

3 设置 SET 部分 SQL

4 例: setSql("name = '老李头'")

5 */

3.2.带条件的crud实验

(1)带条件的查询

1

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

3 T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

4

5 // 根据 entity 条件,查询全部记录

6 List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

7

8 // 根据 Wrapper 条件,查询全部记录

9 List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

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

11 List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

12

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

14 IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

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

16 IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWr

apper);

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

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

(2)带条件的更新

1 @Test

2 void update() {

3 UpdateWrapper<Employee> updateWrapper=new UpdateWrapper<Employee>();

4 updateWrapper.eq("last_name", "lili").eq("age", 18).set("id", 100).set(false, "email", "000@qq.com");

5 empolyeeMapper.update(employee, updateWrapper);

6

7 }

8 }

其中set("id", 100).set(false, "email", "000@qq.com");中email属性设置为false,从执行的sql可以看出,设置为false不会

拼接到最终的执行sql中

(3)带条件的删除

1 // 根据 entity 条件,删除记录2 int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);

3

4 // 根据 columnMap 条件,删除记录

5 int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

测试service

 
 @Resource
EmployeeService employeeService;
 
 /**
 * service方法根据id查询
 */
@Test
void  servicetest(){
    ItEmployee byId = employeeService.getById(1);
    System.out.println(byId);

}


/***
 * service方法他会首先查询,如查询没有则新增有则修改
 */
@Test
void  saveOrUpdate(){
    ItEmployee itEmployee = new ItEmployee(6,"111","123@qq.com","0",12,"1",null,new Date(),null);
    employeeService.saveOrUpdate(itEmployee);
}
 
 
 /***
     * 分页 需要先导入插件,需要新建config文件官网有提供
     */
    @Test
    void page(){
        IPage<ItEmployee> ipage= new Page<>(1,2);
        IPage<ItEmployee> page=employeeService.page(ipage);
        List<ItEmployee> pageRecords = page.getRecords();
        System.out.println(page.getSize());
        System.out.println(page.getTotal());
        System.out.println(pageRecords);
    }

    /***
     * xml分页
     */
    @Test
    void xmlpage(){
        IPage<ItEmployee> ipage=new Page<>(1,2);
        List<ItEmployee> employees = itEmployeeService.getbygender(ipage, "1").getRecords();
        for (ItEmployee employee : employees) {
            System.out.println(employee);
        }

    }

    @Test
    void queryWrapper(){
        QueryWrapper<ItEmployee> queryWrapper=new QueryWrapper<>();
        queryWrapper
                .select("emp_name","emp_email","age")
                .eq("emp_name","李四");

        System.out.println(employeeService.list(queryWrapper));

    }




    /***
     *  根据 entity 条件,查询一条记录
     */
    @Test
   void QueryWrappertest(){
        ItEmployee employee = new ItEmployee();
        employee.setEmpName("王五");
        employee.setGender("0");
        ItEmployee selectone = itEmployeeService.selectone(employee);
        System.out.println(selectone);
    }

    /***
     *  设置带多条件的修改
     */
    @Test
    void UpdateWrappertest(){
        ItEmployee employee = new ItEmployee();
        employee.setEmpName("李四");
        employee.setGender("1");
        UpdateWrapper<ItEmployee> updateWrapper=new UpdateWrapper<>();
//        查询条件emp_name为王五的和gender为1的 set为修改的 set(false, "email", "000@qq.com");中email属性设置为false,从执行的sql可以看出,设置为false不会
//        拼接到最终的执行sql中
//        updateWrapper.eq("emp_name",employee.getEmpName()).eq("gender",employee.getGender()).set("age",13).set(false,"email","wangwu@163.com");

        updateWrapper
                .lambda()
                .set(ItEmployee::getAge,24)
                .eq(ItEmployee::getEmpName,"李四")
                .eq(ItEmployee::getGender,"1")
                ;
        int selectone = itEmployeeService.updateEntityparams(employee, updateWrapper);
        if (selectone>0){
            System.out.println("修改成功!");
        }

    }


    /**
     * 设置带多条件的删除
     */
    @Test
    void  DelWrappertest(){
     QueryWrapper<ItEmployee> employeeQueryWrapper=new QueryWrapper<>();
     employeeQueryWrapper.eq("emp_name","王五").eq("gender","1");
     int delEntityparams = itEmployeeService.DelEntityparams(employeeQueryWrapper);
     if (delEntityparams>0){
         System.out.println("删除成功!");
     }
    }

上面test类中有提到分页

他的分页需要新建config文件官网有提供的

@Configuration
public class mybatisplusConfig {

    //最新版
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
    

}

xml分页的使用

需要新建xml文件,有时候在业务场景比较复杂的情况下是可以自己编写xml进行分页编写的,他也保留mybatis作为半自动化的一款交互

<?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.wq.mybatisplusdemo.demo.dao.ItEmployeedao" >
<select id="getbygender" resultType="com.wq.mybatisplusdemo.demo.entity.ItEmployee">
    select * from it_employee where gender=#{gender}
</select>

</mapper>

@Mapper
public interface ItEmployeedao extends BaseMapper<ItEmployee> {

    /***
     * xml分页
     * @param page
     * @param
     * @return
     */
    IPage<ItEmployee> getbygender(IPage page,String gender);
}

3.mybatis-plus的扩展

扩展

全局ID生成策略

在全局配置文件中: 就不需要再每个Pojo主键上配置了

 mybatis‐plus: 
 global‐config: 
 db‐config: 
 id‐type: auto 

逻辑删除

物理删除: 在删除的时候直接将数据从数据库干掉DELTE

逻辑删除: 从逻辑层面控制删除,通常会在表里添加一个逻辑删除的字段比如 enabled 、is_delete ,数据默认是有效的(值为1),

当用户删除时将数据修改UPDATE 0, 在查询的时候就只查where enabled=1.

1. 需要添加逻辑删除的字段

2. 局部单表逻辑删除,需要在对应的pojo类加入对应的逻辑删除标识字段

@TableLogic // 代表逻辑删除

private Integer flag;

public Integer getFlag() {

return flag;

}

全局逻辑删除配置, 如果进行了全局逻辑删除配置并且指定了,就可以不用在每个pojo类中配置了@TableLogic

mapper-locations: classpath:/mappexxr/*.xml
  global‐config:
    db‐config:
      logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 0 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 1 # 逻辑未删除值(默认为 0)
     id‐type: auto

当执行删除, 将会把逻辑删除字段进行修改当执行查询,会自动查询有效数据 where flag=1

执行 SQL 分析打印

<!--sql性能分析日志-->
<dependency>
    <groupId>p6spy</groupId>
    <artifactId>p6spy</artifactId>
    <version>3.9.1</version>
</dependency>

添加p6spy : spy.properties

 #3.2.1以上使用 
 modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6Ou 
tageFactory 
 #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 秒24 outagedetectioninterval=2 

yml的连接信息需要改动

# 数据源
spring:
  datasource:
    username: root
    password: wq123
    url: jdbc:p6spy:mysql://localhost:3306/stupubdemo?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=10
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver #com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

效果:

数据安全保护

防止删库跑路

1.得到16位随机秘钥

@Test 
 void test(){// 生成 16 位随机 AES 密钥 
 String randomKey = AES.generateRandomKey(); 
 System.out.println(randomKey); 
 } 
 运行结果的 : da12166c7db8a58f 

  1. 根据秘钥加密 数据库连接信息

 @Test 
 void test(){ 
  String url = AES.encrypt("jdbc:mysql://localhost: 3306/mybatisplus?characterEncoding=utf8&useSSL=false 
&serverTimezone=UTC&" , "da12166c7db8a58f"); 
 String uname = AES.encrypt("root" , "da12166c7db8a58f"); 
 String pwd = AES.encrypt("123456" , "da12166c7db8a58f"); 
 System.out.println(url); 
 System.out.println(uname); 
 System.out.println(pwd);11 } 
把数据库的url user pwd等进行加密

3.修改生产的配置文件prod 注意要mpw:开头

# 数据源
spring:
  datasource:
    username: mpw:uO+56CtZiH7WvW0Uttle0w==
    password: mpw:+R96zspi9RpHpagOrFo7jw==
    url: mpw:O97zTPbK6kRCnbNRHvNclC9A1eohqPwv40CKLaI+w678j4njvEsuoTuMkr/hXULdscaFPDQxxFRpLRELduLEsEHCOPEp6JV1JQi+vbgcQg95zCKQWC5PIyXvitTpDCJsIjwlH62hxTochApIXr+6HTNDXfXIj2aOeNMfy87jFx7Ax0fqc/NrAIIka4+Mh7EFeZdbbYvHq0dlzpmNkXhJCLF1upppRVhiSnupk3ANeQ0=
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
logging:
  level:
    root: info
    com.tulingxueyuan: debug
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: enabled  #逻辑删除的字段
      logic-delete-value: 0     #已删除数据
      logic-not-delete-value: 1   #有效数据
      id-type: auto
server:
  port: 8010

  1. 在springboot启动类中添加测试方法

import com.wq.mybatisplusdemo.demo.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
    static EmployeeService employeeService;

    @Autowired
    public void setEmployeeService(EmployeeService employeeService) {
        DemoApplication.employeeService = employeeService;
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
        // 测试数据安全保护下 部署上线能否正确连接数据库
        System.out.println(employeeService.getById(1));
    }

}

4.使用maven进行package进行打包

注意打包的时候你的本地运行还是开发环境,不然打不好的,

默认指向开发

4.打开你打完包后的目录然后进行cmd 在部署的时候需要解密 java -jar xxxx.jar --mpw.key=你的16位随机秘钥 --spring.profiles.active=prod

查询出数据代表部署成功

乐观锁插件使用

第一:什么是乐观锁

悲观锁:悲观锁,正如其名,具有强烈的独占和排他特性。它指的是对数据被外界(包括本系统当前的其他事

务,以及来自外部系统的事务处理)修改持保守态度。因此,在整个数据处理过程中,将数据处于锁定状态。

假设功能并发量非常大,就需要使用synchronized来处理高并发下产生线程不安全问题, 会使其他线程进行挂起等待从

而影响系统吞吐量

乐观锁:乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正

式对数据的冲突与否进行检测,如果发现冲突了,则返回给用户错误的信息,让用户决定如何去做。乐观锁适用于读操作多的场

景,这样可以提高程序的吞吐量。 假设功能产生并发几率极少,采用乐观锁版本机制对比, 如果有冲突 返回给用户错

误的信息

第二:为什么需要锁(并发控制)

在多用户环境中,在同一时间可能会有多个用户更新相同的记录,这会产生冲突。这就是著名的并发性问题

丢失更新:一个事务的更新覆盖了其它事务的更新结果,就是所谓的更新丢失。例如:用户1把值从500改为

8000,用户B把值从500改为200,则多人同时提交同一条记录,后提交的把之前的提交数据覆盖。

脏读:当一个事务读取其它完成一半事务的记录时,就会发生脏读。例如:用户A,B看到的值都是500,用户B

把值改为200,用户A读到的值仍为500。

针对一种问题的解决方案,为解决问题而生的。解决什么问题呢?主要是解决丢失更新问题如下图理解

为了解决这些并发带来的问题。 我们需要引入并发控制机制。

第三:乐观锁使用MyBatisPlus的解决方式

由于锁这个字眼我们需要在数据库加个字段“

version”来控制版本

在类中加个属性

 @Version //这就是控制版本的 
 @TableField(fill = FieldFill.INSERT) //这个方便在添加的时候设置版本初始为1 
 private Integer version; //版本的字段 

下面这个也是MyBatisPlus的一个插件 添加配置文件

@Configuration
public class mybatisplusConfig {

    //最新版
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
//        // 乐观锁的插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }


}

只需要实现MetaObjectHandler就可以了

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        // 插入时:创建时间和修改时间
        this.setFieldValByName("createDate",new Date(),metaObject);
        this.setFieldValByName("modifyDate",new Date(),metaObject);
        //这里的“version”就是指定的字段,设置初始值为1,之后每修改一次+1
        this.setFieldValByName("version",1,metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {

        this.setFieldValByName("modifyDate",new Date(),metaObject);
    }
}

接下来在做增加数据的时候,调用insert添加方法就可以了。

修改的时候呢,我们需要先查人后再做修改,因为我们为了防止问题的发生,需要先去查询版本号比对才进行后续操 作!!

test

/***
 * 乐观锁
 */
@Test
void testCAs(){
    ItEmployee employee =employeeService.getById(1);
    employee.setAge(100);

    ItEmployee employee2 =employeeService.getById(1);
    employee2.setAge(80);

    if (employeeService.updateById(employee)){
        System.out.println("更新成功");
    }
    if (!employeeService.updateById(employee2)){
        System.out.println("请稍后重试!");
    }
}

效果:

4.代码生成器

新建类

public static void main(String[] args) {
        String userName="root";
        String password="wq123";
        String url="jdbc:mysql://localhost:3306/stupubdemo?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=10";

        FastAutoGenerator.create(url, userName, password)
                .globalConfig(builder -> {
                    builder.author("Qi.Wang") // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .fileOverride() // 覆盖已生成文件
                            .outputDir("D://logs")//生成的项目目录
                            .dateType(DateType.TIME_PACK)
                            .commentDate("yyyy-MM-dd"); // 指定输出目录
                })
                .packageConfig(builder -> {
                    builder.parent("com.wq.mybatisplusdemo.demo") // 设置父包名
                            .moduleName("wms") // 设置父包模块名
                            .entity("entity")
                            .service("service")
                            .serviceImpl("service.impl")
                            .mapper("mapper")
                            .xml("mapper.xml")
                            .controller("controller")
                            .other("other")
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D:\\wqproject\\javaproject\\springboot\\springboot_mybatis-plus\\springboot_mybatisplus\\src\\main\\resources\\mappexxr")); // 设置mapperXml生成路径
                })
                .strategyConfig(builder -> {
                    builder.addInclude("it_employee") // 设置需要生成的表名
                            .addTablePrefix("it_"); // 设置过滤表前缀

                })
                .strategyConfig(builder -> {
                    builder.entityBuilder()
                            .enableTableFieldAnnotation()
                            .versionColumnName("version")
                            .versionPropertyName("version")
                            .logicDeleteColumnName("flag")
                            .logicDeletePropertyName("flag")
                            .addSuperEntityColumns("id","create_by","create_date","modify_by","modify_date")
                            .idType(IdType.AUTO)
                            .formatFileName("%sEntity");

                })
                .strategyConfig(builder -> {
                    builder.serviceBuilder()
                            .formatServiceFileName("%sService")
                            .formatServiceImplFileName("%sServiceImpl");
                })

                .strategyConfig(builder -> {
                    builder.mapperBuilder()
                            .enableMapperAnnotation();
                })


//                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();
    }

具体还想生成一些内容可参考官网

效果:

controller、entity mapper service等都帮我生成好了真是一个利器呀!

 


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

举报

相关推荐

0 条评论