码迷,mamicode.com
首页 > 其他好文 > 详细

MybatisPlus

时间:2021-04-23 11:56:15      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:extern   help   拼接   复杂   命名   xtend   分页查询   boot   generator   

官网快速开始-:

https://mp.baomidou.com/guide/quick-start.html#%E5%BC%80%E5%A7%8B%E4%BD%BF%E7%94%A8

传统方式 pojo-dao(连接mybatis,配置mapper.xml文件)- service - controller

使用了mybatis-plus 之后

pojo

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

private Long id;
private String name;
private Integer age;
private String email;
}

 

mapper接口

// 在对应的Mapper上面继承基本的接口 BaseMapper
@Repository // 代表持久层
public interface UserMapper extends BaseMapper<User> {
// 所有的CRUD操作都已经基本完成了
// 你不需要像以前的配置一大堆文件了
}

 

 

注意点:我们需要在主启动类上去扫描我们的mapper包下的所有接口如 @MapperScan(com.kuang.mapper) 

技术图片

 

 

 没有写任何CRUD就已经有了这些方法,就是因为我们继承了父类BaseMapper

public interface UserMapper extends BaseMapper<User>

或者另一个项目的@MapperScan(basePackages = {"com.dao"}),只是命名时候mapper改成了dao而已

技术图片

 

 

 配置日志

我们所有的sql现在都是不可见的,我们希望知道它是怎么执行的,所以我们必须要看日志!

# 配置日志 (系统自带的,控制台输出)
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

CRUD

1. 插入操作

@Test
public void testInsert() {
    User user = new User();
    user.setName("Dainel");
    user.setAge(3);
    user.setEmail("daniel@alibaba.com");

    int result = userMapper.insert(user);// 帮我们自动生成id
    System.out.println(result);// 受影响的行数
    System.out.println(user);// 发现: id自动回填
}

上面的代码我们没有设置 User的id属性,但是插入的时候一样成功,因为mybatisplus会自动伴我们生成一个全局唯一id

2. 主键生成策略

数据库插入的id默认值为:全局的唯一id 这里面id的生成方式有很多比如如下的雪花算法

雪花算法:

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

主键自增

我们需要配置主键自增:

实体类字段上 @TableId(type = IdType.AUTO)

技术图片

数据库字段上一定是自增的,其实可以点开源码看看IdType的具体参数类型,都是可以选择的主键策略

技术图片

 

 

 

3. 更新操作

//测试更新
@Test
public void testUpdate(){
    User user = new User();
    // 通过条件自动拼接动态sql
    user.setId(6L);
    user.setName("关注公众号");// 注意: updateById 但是参数是一个 对象
    int i = userMapper.updateById(user);
    System.out.println(i);
}

//测试更新
@Test
public void testUpdate(){
    User user = new User();
    // 通过条件自动拼接动态sql
    user.setId(6L);
    user.setName("关注公众号");
    user.setAge(18);
    // 注意: updateById 但是参数是一个 对象
    int i = userMapper.updateById(user);
    System.out.println(i);
}

来看一下两个不同的更新测试

技术图片

 

 

所有的sql都是自动帮你动态配置的!

4. 自动填充

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

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

方式一:数据库级别(工作中不允许修改数据库)
技术图片

 

 

 方式二:代码级别

1删除数据库中的默认值、更新操作

技术图片

 

 

 2实体类的字段属性上需要增加注解

//字段添加填充内容
@TableField(fill = FieldFill.INSERT)
private Date createTime;

@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;

技术图片

 

 

 3编写处理器来处理这个注解即可(当然这里官网也有  点击官网的自动填充https://mp.baomidou.com/guide/auto-fill-metainfo.html

package com.kuang.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 // 一定不要忘记把处理器加到IOC容器中
public class MyMetaObjectHandler implements MetaObjectHandler {

    // 插入时候的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ...");
        // setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
        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);
    }

}

5. 乐观锁

在面试过程中,我们经常会被问到乐观锁,悲观锁。

乐观锁:顾名思义,它总是认为不会出现问题,无论干什么都不去上锁!如果出现了问题,再次更新值测试!

悲观锁:顾名思义,它总是认为总是出现问题,无论干什么都上锁!再去操作!

乐观锁实现方式:

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

在mybatisPlus官网里也给我们写了乐观锁插件https://mp.baomidou.com/guide/interceptor-optimistic-locker.html#optimisticlockerinnerinterceptor

技术图片

 

 1 数据库中增加一个version字段

技术图片

 

 技术图片

 

 2 需要实体类加上对应的字段

技术图片

 

 3 注册组件(官网有的)

// 扫描我们的 mapper文件夹
@MapperScan("com.kuang.mapper")
@EnableTransactionManagement
@Configuration
public class MyBatisPlusConfig {

    // 注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
}

技术图片

 

 4 测试一下成功与失败

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

会发现执行的时候自动带上了version操作

技术图片

 

 失败的情况模拟:

技术图片

两个用户都要去修改update操作,但是第一个操作后我们的version就改变了比如加一变成3了 

技术图片

 

 

所以都发现变成了3,那么后面的插入111那个邮箱就会失败,所以最后结果如下图为222

技术图片

 

 

6. 查询操作

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

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

// 按照条件查询之一使用 map
@Test
public void testSelectByMap(){
    HashMap<String, Object> map = new HashMap<>();
    // 自定义要查询
    map.put("name","Dainel");
    map.put("age","6");
    List<User> users = userMapper.selectByMap(map);
    users.forEach(System.out::println);
}

7. 分页查询(重点,网站使用最多)

分页网站频繁使用

  1. 原始使用limit进行分页
  2. pageHelper第三方插件
  3. MybatisPlus内置了分页插件

如何使用MybatisPlus内置了分页插件,首先查看官网https://mp.baomidou.com/guide/page.html

发现官网都是使用拦截器去配置的 ,我们复制官网先。

1 配置拦截器

技术图片

 

 

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

2 直接使用Page对象即可

首先我们查看提高的父类方法,里面有的方法就是带分页的如

技术图片

 

 

里面有两个参数,比如ipage接口,而ipage接口下面也有实现类如page我们直接实现即可,需要一个page我们new一个即可,如下。

// 测试分页查询
@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());
}

技术图片

 

 

8. 删除操作

// 测试删除
@Test
public void testdelete(){
    userMapper.deleteById(6L);
}

// 测试批量删除
@Test
public void testdeleteBatchId(){
    userMapper.deleteBatchIds(Arrays.asList(1287326823914405893L,1287326823914405894L));
}

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

9. 逻辑删除

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

逻辑删除:在数据库中没有被移除,而是通过一个变量让他生效!deleted=0 --> deleted=1

如:管理员可以查看被删除的记录!防止数据的丢失!类似于回收站!因为丢入回收站我们其实还可以看到,并还在

测试:

  1. 在数据库表中增加一个deleted字段技术图片

  2.  实体类中增加属性技术图片

  3. 配置!然后就能看到那些被删了

技术图片

 

 4测试删除

技术图片

 

发现日志里提示走的是更新操作

 技术图片

 

 技术图片

 

 5测试查询

我们再看看逻辑删除后还能不能查询到刚刚逻辑删除的数据

技术图片

 

 

四、性能分析插件

来自官网

我们在平时的开发中,会遇到一些慢sql。解决方案:测试,druid监控…

作用:性能分析拦截器,用于输出每条SQL语句及其执行时间

MyBatisPlus也提供性能分析插件,如果超过这个时间就停止运行!

1导入插件(先要在SpringBoot中配置环境为dev或者test环境!)

// SQL执行效率插件
@Bean
@Profile({"dev","test"})
public PerformanceInterceptor performanceInterceptor(){
    PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
    performanceInterceptor.setMaxTime(100); //ms 设置sql执行的最大时间,如果超过了则不执行
    performanceInterceptor.setFormat(true); // 是否格式化
    return performanceInterceptor;
}

2测试使用

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

就可显示时间,超过就会报错  30没有超过我们设置的100 所以正常运行

技术图片

 

 

 

五、条件构造器

十分重要:wrapper  官网:https://mp.baomidou.com/guide/wrapper.html#abstractwrapper

技术图片

我们写一些复杂的sql就可以使用它来代替!需要什么官方看看,而我们就用官网的QueryWrapper父类试试

其实就是运用wrapper的方法(还可以链式编程)

技术图片

 

 

 再如:

  技术图片

 

 

 技术图片

 

 

 

六、代码生成器

dao、pojo、service、controller都给我自己去编写完成!

官网:https://mp.baomidou.com/guide/generator.html

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

MyBatis-Plus 从 3.0.3 之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖:官网自己去看自己去找

 技术图片

 

 

 技术图片

 

 

 技术图片

 

 

 只需要更改表名即可自动生成代码

技术图片

 

 

最终结果如下

技术图片

 

 

 同理

技术图片

 

 

 这些类都会有了。

下面的来自官网

    public static void main(String[] args) {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");//输出目录
        gc.setAuthor("jobob");//作者
        gc.setOpen(false); //是否打开资源管理器
        // gc.setSwagger2(true); 实体属性 Swagger2 注解
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/ant?useUnicode=true&useSSL=false&characterEncoding=utf8");
        // dsc.setSchemaName("public");
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("密码");
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(scanner("模块名"));
        pc.setParent("com.baomidou.ant");
        mpg.setPackageInfo(pc);

        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };

        // 如果模板引擎是 freemarker
        String templatePath = "/templates/mapper.xml.ftl";
        // 如果模板引擎是 velocity
        // String templatePath = "/templates/mapper.xml.vm";

        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
                        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        /*
        cfg.setFileCreate(new IFileCreate() {
            @Override
            public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
                // 判断自定义文件夹是否需要创建
                checkDir("调用默认方法创建的目录,自定义目录用");
                if (fileType == FileType.MAPPER) {
                    // 已经生成 mapper 文件判断存在,不想重新生成返回 false
                    return !new File(filePath).exists();
                }
                // 允许生成模板文件
                return true;
            }
        });
        */
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();

        // 配置自定义输出模板
        //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
        // templateConfig.setEntity("templates/entity2.java");
        // templateConfig.setService();
        // templateConfig.setController();

        templateConfig.setXml(null);
        mpg.setTemplate(templateConfig);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        // 公共父类
        strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
        // 写于父类中的公共字段
        strategy.setSuperEntityColumns("id");
        strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(pc.getModuleName() + "_");
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }

}

 

MybatisPlus

标签:extern   help   拼接   复杂   命名   xtend   分页查询   boot   generator   

原文地址:https://www.cnblogs.com/yangj-Blog/p/14689106.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!