MybatisPlus实现基本CURD&逻辑删除&代码生成(对标Django系列学习二)

Posted HUTEROX

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MybatisPlus实现基本CURD&逻辑删除&代码生成(对标Django系列学习二)相关的知识,希望对你有一定的参考价值。

Mybatis plus的Id设置

上一篇博文为MyBatisPlus(环境搭建&初体验)

关于这个我们使用一个注解来实现关于表主键ID的操作(前提是你的操作和当前数据库的DDL没有冲突)

我们使用注解 @TableId

例如我们让User表的ID自增

@TableId(type = IdType.AUTO)
public class User {
    //我们可以在这里修改表对象的特性
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

其中我们只需要选择里面的type就好了

那么这里提供了一下几种方案

    AUTO(0), //默认自增
    NONE(1), //为空
    INPUT(2),//自己输入
    ID_WORKER(3),//默认使用,使用雪花算法,golabe unquie
    UUID(4),//使用UUID生成ID golabe unquie
    ID_WORKER_STR(5);//使用字符串表示法

简单的增删改查

Insert

这个好办是吧,每次最好搞的就是他(第一个dome)

回到前面的例子

void InsertUser(){

    User user = new User();
    user.setAge(19);
    user.setEmail("3xxxx2@qq.com");
    user.setName("Huterox");
    int insert = userMapper.insert(user);
    userMapper.selectList(null).forEach(System.out::println);
}

这里就直接插入了

Update

在这里的话首先引入一个数据库操作时间的问题。而在这里又引入了一个修改数据库属性的问题(操作层面上,在Django的ORM里面进行修改是可以直接将数据库的属性给直接进行修改的)

自动更新时间

首先先来说说如何修改时间

方案一:

直接改动数据库表的字段的属性,但是这个显然是不好的,实际的开发当中你也没有这样大的权限。

方案二:

通过我们的注解来实现操作层面上的修改。

@TableField

看到这个就熟悉多了

public class User {
    //我们可以在这里修改表对象的特性
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;

    @TableField(fill = FieldFill.INSERT )
    private Date create_time;
    @TableField(fill = FieldFill.INSERT_UPDATE )
    private Date updata_time;
}

我们在这个表当中增加了这两个变量之后。回到我们的User当中进行修改

加入那两个出发的东西来。

这个两个东西其实只是相当于触发器,真正我们还需要自己写一个注解,不过只是实现他们的接口罢了。


package com.huterox.springbootdome1.Handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import javax.xml.crypto.Data;
import java.util.Date;

@Component //告诉Spring这个是我的组件
@Slf4j //告诉他要输出到日志里面(自己定义log信息)
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill");
        this.setFieldValByName("create_time",new Date(),metaObject);
        this.setFieldValByName("updata_time", new Date(),metaObject);

    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill");
        this.setFieldValByName("updata_time", new Date(),metaObject);
    }
}

到此我们就可以实现这个自动跟时间的功能了,而且好处是这个时间是和我们所在时区对应的,忘不了在Django当中由于时区和配置问题的原因本来可以自动加入的搞得我们也不得不手写时间方法。

说到这里有涉及到锁的玩意,也就是同步更新数据的时候的一些问题。这个说句大实话我在玩Django的时候没怎么去看这玩意咋玩的,惭愧惭愧。

那么这里涉及到两个锁

乐观锁

这玩意就是在进行操作的时候不加锁,直到出现问题的时候才会去检查问题。

那这个是怎么实现的呢,简单加一个记录,每次更新的时候都会加上一个记录,当发现这个记录不对的时候就更新失败。那么这里的记录叫做version

原理很简单

1.取出字段当中version 的值假设一开始为1,执行完之后version+1此时的值为2,但是在插入修改数据之前的值是1这个暂时没变,那么更新值的时候会先把原来的version对应的那一组数据更新之后version=2

2.假设现在又来了一个线程他同时在执行这个过程,但是他先完成更新操作,那么这个时候我们的version的值就为2,这个时候显然对于另一个执行更慢的线程来说它要更新version=1的那一组数据,但是此时version=2条件不成立不更新操作。

这样一来就可以保证数据安全只有一个线程对数据进行了更新。

那么在这里操作如下:

1.修改表,在里面加入一个字段 version

2.修改实体类

@Version
private Integer version;

3.注册

这里面我们再搞一个配置类,我们的所有的配置往里面怼

package com.huterox.springbootdome1.config;

import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@MapperScan("com.huterox.springbootdome1.Mapper") //扫描Mapper
@Configuration //告诉SpringBoot这是配置类在这里找
@EnableTransactionManagement //告诉它这是个事务
//这是一个配置类所以的配置相关的事情我们应该在这里完成
public class MyBatisPlusConfig {
    //注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }
}

悲观锁

这个没查到在plus里面

这个就很尴尬

不过其实我们还是有办法的那就是直接上mybatis的原生写法,手撸sql。

更新这个简单

void Update(){
    User user = new User();
    user.setId(1L);
    userMapper.updateById(user);
    

}

但是这个只是简单的操作,后面还可以实现比较复杂的。

查询

这里先说两个方法

第一个直接通过ID来找

userMapper.selectById(1L)
userMapper.deleteBatchIds(Arrays.asList(1L,2L));

第二个通过Map来找

HashMap<String,Object> map = new HashMap();
map.put("id",1L);
map.put("username","Huterox");
userMapper.selectByMap(map);
// 这里就可以找到了同时满足条件的


wrapper条件构造器查询

这个主要是让我们写个条件构造器的玩意,这玩意说句大实话有点像Django 过滤器的玩意。

挺好用的主要和Map有点像。

QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name").isNotNull("email");
userMapper.selectList(wrapper);
//直接链式查询这个和Django fitler类似

当然这里可不止这些

https://baomidou.com/guide/wrapper.html#having

其实很多方法和Django ORM的过滤器的过滤方式的名称类似。

分页查询

这个咱们还是有原生的或者是mybatisplus带的。

我们直接写分页配置就可以。

public PaginationInterceptor paginationInterceptor(){
    return new PaginationInterceptor();
}

这个就和Django来比不太友好了,但是也没办法,当前还是好好学吧,看看有木有可能性再次简化:Spring-Django?

Page<User> page = new Page<>(1,5)//第几页一页几条数据
userMapper.selectPage(page,null)//第二个是要给wrapper做高级查询的
page.getRecords().forEach(System.out::println)

这个时候数据全部查询出来了只是先让page包装一下,所以我们需要对page进行操作。

具体的就看操作对象了,我现在已经可以想到接下来如果我要重构white hole的痛苦了~ !~

删除

真-删除

这个和那玩意一样

逻辑删除

这个其实就是ORM的objects的Manager

这里写一个删除的字段 0 还在 1 逻辑上删了。这里不得不说一下Django在这方面做的不错!但是这里的话页不难,只不过人家一行代码的事情杯加了一些步骤,可以想想直接在mybatis里面怼是啥感觉!

老规矩,加字段(数据库里面),加注解,加配置。

@TableLogic //逻辑删除注解
private Integer deleted;
public ISqlInjector sqlInjector(){
    return new LogicSqlInjector();
}

到这一步还不够在配置一些springboot才行

mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

这个时候操作不便,删除的。

性能分析插件

这个其实还是说给个看看sql的执行时间设置一个超时时间,一但超时了就会显示出对应的sql语句之后就进行优化。(看来还是得恶补一下sql了)

这里直接导入插件就好了。

@Bean
@Profile({"dev","test"})
public PerformanceInterceptor performanceInterceptor(){
    PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
    performanceInterceptor.setMaxTime(100);//毫秒为单位
    performanceInterceptor.setFormat(true);//格式化sql
    return performanceInterceptor;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sLO7BYJi-1634372405749)(C:\\Users\\31395\\AppData\\Roaming\\Typora\\typora-user-images\\image-20211015001342578.png)]

效果就这样

代码自动生成

这个功能其实就是很久以前在Django里面说到模型反射。

python maganer.py inspectdb > APP/models.py

那么在这里的话用的是 AutoGenerator来帮助我们搞

这里我们需要构建代码生成器对象

实例一个自动生成器,然后写配置

public class Inspectdb{
    public static void main(String[] args){
        AutoGenerator auto = new AutoGenerator();
        //2.配置策略其实相当于告诉它把代码放到哪里去,之类的
        //毕竟这是一个 严谨(繁琐)的工程嘛
        //这里分几大块,一个是在项目里面的设置例如你的代码生成在哪里
        //还有就是你的数据库相关的设置例如前面的自动填充日期之类的
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath+"/src/main/java");
        gc.setAuthor("Huterox");//作者生成
        gc.setOpen(false);//是否打开文件夹,生成后
        gc.setFileOverride(false);//是否覆盖
        gc.setServiceName("%sService");//去掉前缀
        
        gc.setIdType(IdType.ID_WOEKER);
        gc.setDateType(DateType.ONLY_DATE);
        gc.setSwagger2(true);
       	auto.setGlobalConfig(gc);
        
        //设置数据源
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl();
        dsc.setDriverName();
        dsc.setPassword();
        dsc.setDbType(DbType.mysql);
        auto.setDataSource(dsc);
        
        //包的配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("blog");//在com.huterox的包下面生成一个blog包
        pc.setParent("com.huterox");
        pc.setEntity("pojo"); //这些都在blog包下面
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setController("controller");
        auto.sestPackageInfo(pc);
        
        //配置策略例如乐观锁之类的,哪张表进行映射
        
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("user");//哪张表先映射,strategy.setInclude("user","blog"...)
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underlone_to_camel);
        
        //strategy.setEntityClass("父类实体,没有就不要设置");
        strategy.setEntityLombokModel(true);//自动生成注解Lombok
       // strategy.setRestControllerStyle(true);
        
        //逻辑删除
        strategy.setLogicDeleteFieldName("deleted");
        //自动填充策略(日期生成)
        TableFill gmtCreate = new TableFill("gmt_create",FieldFill.INSERT);
        TableFill gmtModified = new TableFill("gmt_modified",FieldFill.INSERT_UPDATE);
        ArraryList<TableFill> tableFills = new ArraryList<>();
        tableFills.add(gmtCreate);
        tableFills.add(gmtModified);
        strategy.setTableFillList(tableFills);
        
        //乐观锁配置
        strategy.setVersionFieldName("version");
        
        //对生成的变量进行美化的设置
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true); //采用下划线命名法
        
      
        auto.setStrategy(strategy);
        
        
        
        auto.execute();
    }
}

总结

目前这些玩意还是基础使用,接下来是如何自己根据自己的业务去自定义查询,以及在mybatisplus的关系对应中如何实现(联表查询,一对多,多对多,一对一之类的怎么搞,当然我并没有继续直接上mybatis,原因无他我不喜欢这种半自动化框架,对于一个连简单查询都需要手写Sql的框架我实在提不起一丁点兴趣,而且我为此还需要手动去实现一些SQL安全,我一开始就是玩爬虫的后面玩渗透对这些玩意我不得不铭感一点,当然这也并不是意味着我绝对相信别人的框架做出的安全处理,只是有要比没有好太多…)

以上是关于MybatisPlus实现基本CURD&逻辑删除&代码生成(对标Django系列学习二)的主要内容,如果未能解决你的问题,请参考以下文章

使用Mybatis实现CURD后,新增几张表用MybatisPlus实现CURD

mybatisplus是啥

MyBatisPlus

MybatisPlus之-----BaseMapper

Spring系列——MybatisPlus

通过Http接口及SolrNet 两种方法基于Solr5.5.1 实现CURD