Mybatis-Plus

牛啊!!!

简化mybatis的操作,不用写xml配置文件,也就是省略了写sql的操作

实际在springboot项目中直接创建mapper类后继承basemapper类就可以实现所有的sql操作!

image-20220121203528231

进行日志的配置

主键生成策略

在我们新添加一个用户的时候,若不加主键,则会根据雪花策略生成id值

雪花算法:

snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。可以保证几乎全球唯一!

public enum IdType {
    AUTO(0), //id自增
    NONE(1), //未设置主键
    INPUT(2), //手动输入
    ID_WORKER(3), //默认值,全局唯一id
    UUID(4), //全局唯一id,uuid
    ID_WORKER_STR(5); //ID_WORKER的字符串表示法
}

在pojo包中该类的id属性上使用@TableId注解

@TableId(type = IdType.ID_WORKER)就是默认的全局唯一主键

@TableId(type = IdType.ID_AUTO)就是自增主键

@TableId(type = IdType.ID_INPUT)就是手动输入主键否则插入null

@TableId(type = IdType.ID_UUID)就是生成全局唯一id uuid

@TableId(type = IdType.ID_WORKER_STR)就是字符串表示的默认全局唯一主键

自动填充

创建时间、修改时间!这些操作一般自动化完成的,我们不希望手动更新!

阿里巴巴开发手册:所有的数据库表:gmt_create、gmt_modified几乎所有表都要配置上!而且需要自动化!

方式一:数据库级别(工作中不建议这么做)

在表中新增字段create_time、update_time

image-20220121215302679

  1. 再次测试插入方法,需要先把实体类同步!
private Date creteTime;
private Date updateTime;

方式二:代码级别

  • 输出数据库中的默认值、更新操作

image-20220121215616193

  • 在实体类字段属性上需要注释

    //字段添加填充内容
    @TableField(fill = FieldFill.INSERT)
    private Date creteTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    
  • 编写处理器处理注解!

package com.zyc.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 java.util.Date;


@Slf4j
@Component
public class myHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }

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

  • 测试插入
  • 测试更新、观察时间即可!

乐观锁

乐观锁首先就是无论做什么操作都不加锁,如果出现问题就更新值去测试。

乐观锁的实现,就是给数据库中每个实体类加一个version字段,然后sql语句在进行操作的时候会带上当前的version,然后进行判断,若两个version的值相同的话,那么证明操作被允许,结束操作后给version

值加上1,这样如果出现多线程操作统一数据的时候,就可以凭借version字段进行避免出现数据不一致的情况。

乐观锁实现方式:

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

测试乐观锁的插件

  1. 数据库中添加version字段

    image-20220122155835299

  2. 实体类中添加version字段

    //乐观锁的实现
    @Version
    private int version;
    
  3. 注册组件

    package com.zyc.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.zyc.mapper")
    @EnableTransactionManagement  //自动管理事务(默认也是开启的)
    @Configuration  //配置类
    public class MybaitsPlusConfig {
    
        //注册乐观锁插件
        @Bean
        public OptimisticLockerInterceptor optimisticLockerInterceptor() {
            return new OptimisticLockerInterceptor();
        }
    }
    
  4. 测试乐观锁

//测试乐观锁成功!
@Test
public void testOptimisticLocker1() {
    //1.查询用户信息
    User user = userMapper.selectById(1L);
    //2.修改用户信息
    user.setName("godfrey");
    user.setEmail("13610506606@163.com");
    //3.执行更新操作
    userMapper.updateById(user);
}


//测试乐观锁失败!多线程下
@Test
public void testOptimisticLocker2() {
    //线程1
    User user1 = userMapper.selectById(1L);
    user1.setName("godfrey111");
    user1.setEmail("13610506606@163.com");

    //模拟另外一个线程执行插队操作
    User user2 = userMapper.selectById(1L);
    user2.setName("godfrey222");
    user2.setEmail("13610506606@163.com");
    userMapper.updateById(user2);

    //自旋锁多次操作尝试提交
    userMapper.updateById(user1);
}

image-20220122160507935

image-20220122160613565

查询操作

//测试查询
@Test
public void testSelectById() {
    User user = userMapper.selectById(1L);
    System.out.println(user);
}

//测试批量查询
@Test
public void testSelectByBatchId() {
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));
    users.forEach(System.out::println);
}

//条件查询之一 使用map操作
@Test
public void testSelectBatchIds() {
    HashMap<String, Object> map = new HashMap<>();
    //自定义查询
    map.put("name","Tom");
    map.put("age",28);

    List<User> users = userMapper.selectByMap(map);
    users.forEach(System.out::println);
}

分页测试**

牛!

分页在网站中使用非常多!

  1. 原始limit进行分页
  2. pageHelper第三方插件
  3. MP其实也内置了分页插件

配置分页插件

//分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
    return new PaginationInterceptor();
}

测试分页

//测试分页查询
@Test
public void testPage() {
    //参数一:当前页
    //参数二:页面大小
    //使用了分页插件之后,所有的分页操作页变得简单了
    Page<User> page = new Page<>(1,5);
    userMapper.selectPage(page,null);

    page.getRecords().forEach(System.out::println);
    System.out.println(page.getTotal());
}

其中这个page类中有很多的方法,查询总数,当前数,是否有下一页等,但是效率不高因为在每次分页操作前都会执行一遍查询当前数据库总数

image-20220122162515231

删除操作

//通过id删除
@Test
public void testDeleteById() {
    userMapper.deleteById(8L);
}

//通过id批量删除
@Test
public void testDeleteBatchId() {
    userMapper.deleteBatchIds(Arrays.asList(6L, 7L));
}

//通过map删除
@Test
public void testDeleteMap() {
    HashMap<String, Object> map = new HashMap<>();
    map.put("name", "godfrey");
    userMapper.deleteByMap(map);
}

逻辑删除

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

逻辑删除:就是在数据库中并没有删除,而是通过一个变量来让他失效,设置deleted字段进行判断

eg:管理员可以查看被删除的操作记录

1.添加字段

image-20220122163642464

2.实体类添加字段

//逻辑删除字段
    private Integer deleted;

3.配置文件中配置逻辑删除

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.配置逻辑删除插件

//逻辑删除插件
    @Bean
    public ISqlInjector iSqlInjector(){
        return  new LogicSqlInjector();
    }

5.测试

性能分析 插件

主要是可以设置执行sql的时间,把超过sql时间,也就是慢sql的语句挑出来

导入依赖
p6spy p6spy 3.9.0
修改数据库连接配置

数据库连接配置

spring.datasource.driver-class-name=com.p6spy.engine.spy.P6SpyDriver
spring.datasource.url=jdbc:p6spy:mysql://localhost:3306/mybatis_plus?userSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8

新建spy.properties 并设置参数

#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#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

日期格式gui

dateformat=yyyy-MM-dd HH:mm:ss

实际驱动可多个

#driverlist=org.h2.Driver

是否开启慢SQL记录

outagedetection=true

慢SQL记录标准 2 秒

outagedetectioninterval=2

条件查询**

帮助我们解决复杂的sql语句,使用wapper来解决.非常厉害

测试一

@Test
void test1() {
//查询name不为空的用户,并且邮箱不为空的,年龄大于等于12
QueryWrapper wapper = new QueryWrapper<>();
wapper.isNotNull(“name”)
.isNotNull(“email”)
.ge(“age”, 12);
userMapper.selectList(wapper).forEach(System.out::println);
}

测试二

@Test
void test2() {
//查询名字为Tom
QueryWrapper wapper = new QueryWrapper<>();
wapper.eq(“name”,“Tom”);
User user = userMapper.selectOne(wapper);
System.out.println(user);
}

测试三

//范围查询
@Test
void test3() {
//查询年龄在20~30岁之间的用户
QueryWrapper wapper = new QueryWrapper<>();
wapper.between(“age”, 20, 30);//区间
System.out.println(userMapper.selectCount(wapper));//查询结果数
}

测试四

//模糊查询
@Test
void test4() {
//查询名字有
QueryWrapper wapper = new QueryWrapper<>();
wapper.notLike(“name”,“e”)//%e%
.likeRight(“email”,“t”);//t%
List<Map<String, Object>> maps = userMapper.selectMaps(wapper);
maps.forEach(System.out::println);
}

测试五

//子查询
@Test
void test5() {
QueryWrapper wapper = new QueryWrapper<>();
//id在子查询中查出来
wapper.inSql(“id”,“select id from user where id<3”);
List objects = userMapper.selectObjs(wapper);
objects.forEach(System.out::println);
}

测试六
//排序
@Test
void test6() {
    QueryWrapper<User> wapper = new QueryWrapper<>();
    //通过id进行排序
    wapper.orderByDesc("id");
    userMapper.selectList(wapper).forEach(System.out::println);
}

代码生成器

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.lqf</groupId>
    <artifactId>springboot-mybatis-plus-genrator</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>springboot-mybatis-plus-genrator</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--lombok用来简化实体类-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.3</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>


配置文件,可用可不用

#此处为本项目src所在路径(代码生成器输出路径)
OutputDir=D:/V/springboot-mybatis-plus-genrator/src/main/java
#mapper.xml的生成位置
OutputDirXml=D:/V/springboot-mybatis-plus-genrator/src/main/resources
#数据库表名(此处切不可为空,如果为空,则默认读取数据库的所有表名)
tableName=fy_currency_log
#装代码的文件夹名
className=crm
#设置作者
author=lqf
#正常情况下,下面的代码无需修改!!!!!!!!!!
#自定义包路径
parent=com.lqf.springbootmybatisplusgenrator
#数据库地址
url=jdbc:mysql://******:3306/crm?useUnicode=true&characterEncoding=utf-8&tinyInt1isBit=false
userName=***
password=***


下面是生成代码实例

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;

/**
 * <p>
 *     代码生成器
 * </p>
 */
public class MpGenerator {

    public static void main(String[] args) throws InterruptedException {

        //用来获取Mybatis-Plus.properties文件的配置信息
        final ResourceBundle rb = ResourceBundle.getBundle("mybatis-plus");

        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        gc.setOutputDir(rb.getString("OutputDir"));
        gc.setOpen(false);
        gc.setBaseResultMap(true);
        gc.setBaseColumnList(true);
        gc.setAuthor(rb.getString("author"));
        gc.setMapperName("%sMapper");
        gc.setXmlName("%sMapper");
        gc.setServiceName("%sService");
        gc.setServiceImplName("%sServiceImpl");
        gc.setControllerName("%sController");
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDbType(DbType.MYSQL);
        dsc.setUrl(rb.getString("url"));
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUsername(rb.getString("userName"));
        dsc.setPassword(rb.getString("password"));
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setParent(rb.getString("parent"));
        pc.setController("controller." + rb.getString("className"));
        pc.setService("service." + rb.getString("className"));
        pc.setServiceImpl("service." + rb.getString("className") + ".impl");
        pc.setEntity("bean." + rb.getString("className"));
        pc.setMapper("dao." + rb.getString("className"));
        mpg.setPackageInfo(pc);

        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };
        List<FileOutConfig> focList = new ArrayList<>();
        focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                return rb.getString("OutputDirXml") + "/mapper/" + rb.getString("className") + "/" + tableInfo.getEntityName() + StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);
        mpg.setTemplate(new TemplateConfig().setXml(null));

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        strategy.setInclude(new String[]{rb.getString("tableName")});
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();

    }
}





**可以使用idea的插件easycode进行编写**
Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐