Mybatis-plus >>>>>从入门到入狱_mybatisplus中的->作用是什么-程序员宅基地

技术标签: 工具搭建  mybatis  

一、什么是Mybatis-plus

Mybatis的出现 是为了简化JDBC的复杂操作,而Mybatis-plus的出现则是为了简化Mybatis的操作,它不会改变mybatis原有的东西,只会在原有的基础上增加功能,可以说,它是非入侵式的,蕴含了AOP的思想

在这里插入图片描述

二、Mybatis-plus的特点

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 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操作CRUD的数据库

三、快速入门

  • 现有一张 User 表,其表结构如下:
id name age email
1 Jone 18 [email protected]
2 Jack 20 [email protected]
3 Tom 28 [email protected]
4 Sandy 21 [email protected]
5 Billie 24 [email protected]
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)
);
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, '[email protected]'),
(2, 'Jack', 20, '[email protected]'),
(3, 'Tom', 28, '[email protected]'),
(4, 'Sandy', 21, '[email protected]'),
(5, 'Billie', 24, '[email protected]');
  • 创建一个SpringBoot项目

  • 添加MybatisPlus启动器依赖

         <!-- mybatis-plus-启动器 -->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.4.3</version>
            </dependency>
    
            <dependency>
                <groupId>com.h2database</groupId>
                <artifactId>h2</artifactId>
                <scope>runtime</scope>
            </dependency>
    
  • 编写实体类

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
          
        private Long id;
        private String name;
        private Integer age;
        private String email;
    }
    
  • 编写Mapper类

@Mapper
@Repository
public interface UserMapper  extends BaseMapper<User> {
    

}
/*
		继承BaseMapper<T>类 T是一个泛型  这里填入我们的实体类
		我们就可以直接使用MybatisPlus为我们封装好的CRUD方法

*/
  • 编写数据库数据源和日志

    #数据库连接配置  mysql 8.0版本的多了时区设置 GMT%2b8就是我们东八区的时区
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/mybatis-plus?serverTimezone=GMT%2b8
        username: root
        password: 123456
    #日志配置 默认控制台输出  这里我们使用默认的日志输出
    mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    
  • 测试

        @Autowired
        UserMapper userMapper;
        @Test
        void contextLoads() {
          
            List<User> users = userMapper.selectList(null);
            for (User user : users) {
          
                System.out.println(user);
            }
        }
    

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

这样 我们的Mybatis-Plus环境就算搭建完成了

四、CRUD的探究

Insert

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

查看insert的方法 只有一个 返回值是一个entity实体类对象

我们在不插入ID的情况下 进行测试看看发生什么

   //插入测试
    @Test
    public void text1(){
    
        User user = new User();
        user.setAge(18);
        user.setName("狂神");
        user.setEmail("[email protected]");
        userMapper.insert(user);
    }

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

通过控制台输出 我们发现 它自动给我们生成了一个Long类型的数字 那么它是怎么来的呢?

原来,Mybatis-plus的insert语句中,内置了主键自增策略,当我们的ID为NULL时,它会自动给我们生成一串数字,这串数字是由雪花算法产生的,而产生的前提是ID的类型必须Long类型,雪花算法也是它的默认类型

注意:

如果我们的ID类型为其他类型。且插入的时候为NULL 运行程序就会报错

Caused by: 
org.apache.ibatis.reflection.ReflectionException: Could not set property 'id' of 'class com.llf.Pojo.User' with value '1418934148565385218' Cause: java.lang.IllegalArgumentException: argument type mismatch
    翻译:无法将long类型的值'1418934148565385218'赋给ID   
雪花算法是什么呢?

说白了 它就是一种随机生成主键的算法 它有以下特点

  • 最高位是符号位,始终为0,不可用。
  • 41位的时间序列,精确到毫秒级,41位的长度可以使用69年。时间位还有一个很重要的作用是可以根据时间进行排序。
  • 10位的机器标识,10位的长度最多支持部署1024个节点。
  • 12位的计数序列号,序列号即一系列的自增id,可以支持同一节点同一毫秒生成多个ID序号,12位的计数序列号支持每个节点每毫秒产生4096个ID序号。
其他的主键生成策略

在mybatis-plus中,除了默认的雪花算法还有许多主键生成策略

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

  • ASSIGN_ID

    Twitter的分布式自增ID算法 雪花算法 就是我们默认的主键生成策略

    形式:1418884175761063937

  • ASSIGN_UUID

    形式:6904b36e-e220-2fcf-4e00-23c3449e1e24

    随机生成UUID,UUID 是 通用唯一识别码(Universally Unique Identifier)的缩写 优点是

    ​ 优点:性能非常高,JDK自带本地生成,无网络消耗

    ​ 缺点:(1)只保证了唯一性,趋势递增。

    ​ (2)无序,无法预测他的生成规则,不能生成递增有序的数字。

    ​ (3)mysql官方推荐主键越短越好,UUID包含32个16位进制的字母数字,每一个都很长。

    ​ (4)B+树索引的分裂。主键是包含索引的,mysql的索引是通过B+树来实现的,因为UUID是无序的,插入无序,不但会导致一些中间节点产生分裂,也会白白创造很多不饱和的节点,大大降低了数据库插入的性能。

  • AUTO

    主键自增,也是最简单的主键生成策略,但是实现的前提必须是数据库必须打开主键自增的设置

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

  • INPUT

    自己输入 即自己Set注入

     User user = userMapper.selectById(1l);
      user.setId(2L);
    userMapper.updateById(user);
    

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

  • NONE

    什么也不输入 如果这张表中没有主键,即为NULL 但基本上不会这么做。

delete

物理删除:delete 语句就是物理删除 一旦删除 就没有了
逻辑删除:通过代码设置 在查询的时候不显示 实际上数据库中还有 只是状态不同了 类似于回收站

物理删除

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

  • deleteById

    通过单个id删除

  • deleteBatchIds

    通过多个id同时删除

  • deleteByMap

    通过一个Map集合删除

        @Test
        public void text5(){
          
            userMapper.deleteById(1418846421555712001l);
            System.out.println("通过id删除成功");
            userMapper.deleteBatchIds(Arrays.asList(1418844779586318338l,1418844779586318337l));
            System.out.println("多个ID删除成功");
            HashMap<String, Object> map = new HashMap<>();
            map.put("id","10");
            userMapper.deleteByMap(map);
            System.out.println("通过map删除成功");
        }
    

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

逻辑删除
  • 逻辑删除的本质就是通过查询不同状态 来显示数据 所以我们在数据库中增加字段deleted

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

我们设定0为正常显示 1为不显示 并设置默认值为0

  • 然后在Pojo实体类中完善字段 并添加注解
    //逻辑删除注解
    @TableLogic
    private Integer deleted;
  • 在application中进行01显示设置
mybatis-plus:
  global-config:
    db-config:
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

  • 测试
userMapper.deleteById(4);
 System.out.println("通过id删除成功");

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

这时我们可以发现删除语句 在后台已经变成了更新语句

  • 查询

     @Test
        void contextLoads() {
          
            List<User> users = userMapper.selectList(null);
            for (User user : users) {
          
                System.out.println(user);
            }
        }
    

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

通过查询 和数据库查询 我们发现这些值在数据库中依然存在 只是查询不到了 这就表明实现了逻辑删除

updete

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

更新 只有两种方法 ,一种是传入一个对象,一种是传入对象+构造器Wrapper 关于构造器 我们这里先让他为null

  • update

    传入一个对象 修改所有值 相当于普通更新 没有where条件条件(Wapper构造器可以添加条件 但这里先不用)

	@Test
    public void text8(){
    
        User user = new User();
        user.setId(1418932799022907393L);
        user.setAge(18);
        user.setName("狂");
        user.setEmail("[email protected]");
        userMapper.update(user,null);

    }

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

他把所有信息都更改了

  • updateById

顾名思义 传入一个对象 通过id修改内容

  @Test
    public void text8(){
    
        User user1 = new User();
        user1.setId(11L);
        user1.setAge(1);

        // userMapper.update(user,null);
        userMapper.updateById(user1);
    }

在这里插入图片描述

自动填充

按照规范,我们在数据库设计的过程中会加入create_time、update_time,但是这些时间理论上应该是自动生成,而不是我们一个一个New Data()实现的 Mybatis-Plus就为我们完成了这个功能

  • 在数据库添加字段 create_time、update_time
  • 完善实体类,在属性create_time、update_time上添加注解
    //在插入时填充时间
    @TableField(fill = FieldFill.INSERT_UPDATE )
    private Date  createTime;
    //更新时更新时间
    @TableField(fill = FieldFill.UPDATE)
    private Date   updateTime;

  • 创建MetaObjectHandler类,进行设置
package com.llf.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
//添加@Componment注解 表示被Spring托管
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    
    /**
     * 自动填充时间
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
    
        log.info("start insert fill ....");
        //插入时填充 create_time、update_time时间
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
    
        log.info("start update fill ....");
        //修改时 填充update_time时间
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

  • 测试

在这里插入图片描述

select

在这里插入图片描述

和删除的方法一样 就不过多叙述

五、乐观锁

什么是乐观锁?

乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回给用户错误的信息,让用户决定如何去做。

简单来说,就是 比较乐观,认为程序是不会出毛病的,如果出毛病了 就进行解决

而悲观锁与其相反,悲观锁在做任何事的时候,都会提前检查,这样虽然提高了安全性,但使效率大大降低

实现乐观锁

  • 首先在数据库添加字段 version 使其默认值为1
  • 完善实体类
//添加注解 告诉系统 这是一个乐观锁
@Version
    private  Integer version;
  • 创建config类 配置引入插件配置(全是官网原码,我们直接复制就行)
package com.llf.config;


import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

//打开事务管理 即事务回滚之类的操作
@EnableTransactionManagement
// 告诉springBoot  这是spring配置类
@Configuration
public class MybatisplusConfig {
    
    /**
    乐观锁: OptimisticLockerInnerInterceptor
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
    
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }

}

  • 测试
//乐观锁成功测试
// 所谓成功,就是对象A查询数据库后,拿到Version 在执行更新操作的时候 将拿到的version与此时数据库中对应的version进行对比,刚好一致  因此  就成功了
@Test
public void text2(){
    
    User user = userMapper.selectById(1l);
    user.setId(11L);
    user.setName("过");
    userMapper.updateById(user);
}

//乐观锁失败测试
// 所谓失败,就是一个对象A查询完数据库后,在提交更新操作之前,另一个对象B也查询了数据库,并完成了更新操作,这时数据库中的version是A查询的version+1,这显然与A查询的version不相等 所以就失败了
@Test
public void text3(){
    
    User user = userMapper.selectById(1l);
    user.setId(2L);
    user.setName("杨过");
    User user2 = userMapper.selectById(1l);
    user.setId(2L);
    user.setName("杨过");
    userMapper.updateById(user2);
    userMapper.updateById(user);
}

在这里插入图片描述

六、分页

Mybatis-plus为我们准备了比PageHelper更为方便的分页插件

  • 引入分页插件
   /**
   
     * 新的分页插件,一缓和二缓遵循mybatis的规则,
     * 需要设置 MybatisConfiguration#useDeprecatedExecutor = false
     * 避免缓存出现问题(该属性会在旧插件移除后一同移除)
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor1() {
    
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
        return interceptor;
    }

将其放在 乐观锁的config配置文件中 因为同属于MybatisPlus配置文件

  • 测试
    //分页查寻
    @Test
    public void text7(){
    
        //第1页 显示3个  第一个参数是Current  第二个参数是Size
        Page<User> page = new Page<>(1,3);
        userMapper.selectPage(page,null);
       //records  总记录
        List<User> userList = page.getRecords();
        for (User user : userList) {
    
            System.out.println(user);
        }
        long size = page.getSize();
        System.out.println("页面显示大小"+size);
        long total = page.getTotal();
        System.out.println("总数量"+total);
        long current = page.getCurrent();
        System.out.println("当前页码"+current);
        long pages = page.getPages();
        System.out.println("总页数"+pages);

    }

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

和PageHelper一样 在查询之前 横切了一个count(*)的查询 来查询total

在 查询后自动添加limit 分页查询 得到结果

	总记录:records  
页面显示大小":size
总数量":total				总记录是一个集合  总数量是一个值
当前页码":current
"总页数":pages

七、条件构造器

条件构造器就好比是一个能够自动帮你拼接sql的工具,按照约定大于配置的理念,我们只需要在合适的地方填入合适的参数,条件构造器就能帮我们完成复杂查询、子查询等操作

在这里插入图片描述

https://mp.baomidou.com/guide/wrapper.html#select

官方提供了许多接口供我们使用,且每一个接口的使用、参数说明都讲的很清楚

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

  • 测试

        @Test
        public void test1(){
          
            /*
            模糊查询  查询名字里有狂字的所有人
            查询操作 就创建QueryWrapper<>()
            对应的 什么操作 就创建什么操作的Wrapper
             */
            QueryWrapper<User> wrapper = new QueryWrapper<>();
           wrapper.like("name","狂");
           //如果查询一个人 就使用selectOne() 这样效率更快
            List<Object> list = userMapper.selectObjs(wrapper);
            for (Object o : list) {
          
                System.out.println(o);
            }
    
        }
        @Test
        void test2(){
          
            //查询eamil以T开头的人
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            //以xxx开头 就是xx%  也就是likeRight
            //以xxx结尾 就是%xxx  也就是likeLeft
            wrapper.likeRight("email","t");
            List<Object> list = userMapper.selectObjs(wrapper);
            for (Object o : list) {
          
                System.out.println(o);
        }
    }
        @Test
        void test3(){
          
            //查询名字不为空的人
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.isNotNull("name");
            List<Object> objects = userMapper.selectObjs(wrapper);
            for (Object object : objects) {
          
                System.out.println(object);
            }
        }
    

更多的例子 可以参考官方例子

八、代码生成器

代码生成器 也就是我们常说的逆向工程 他可以帮助我们自动生成底层的代码框架。Pojo、Mapper、service、Controller

且支持自动生成Swagger2API注解 乐观锁、自动填充等等

  • 导入依赖

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

<!-- 代码生成器-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.4.1</version>
</dependency>
<!-- 引擎模板-->
<!-- https://mvnrepository.com/artifact/org.apache.velocity/velocity-engine-core -->
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.3</version>
</dependency>
<!-- freemarker-->
    <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.31</version>
        </dependency>

代码

package com.llf;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
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.TableFill;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
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.Scanner;

public class MybatisPlusCode {
    


    /**
     * <p>
     * 读取控制台内容
     * </p>
     */
    public static String scanner(String tip) {
    
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + ":");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
    
            String ipt = scanner.next();
            if (StringUtils.isNotBlank(ipt)) {
    
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "!");
    }

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

        /**
         全局配置
         */
        GlobalConfig gc = new GlobalConfig();
        //扫描当前路径
        String projectPath = System.getProperty("user.dir");
        //代码生成在/src/main/java目录下
        gc.setOutputDir(projectPath + "/src/main/java");
        //作者名字
        gc.setAuthor("llf");
        //是否打开生成后的文件夹
        gc.setOpen(false);
        //实体属性 Swagger2 注解
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);

        /**
         *
         / 数据源配置
         *
         */
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/mybatis-plus? useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
        // dsc.setSchemaName("public");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        //将数据源仍进代码生成器
        mpg.setDataSource(dsc);

        /**
         * 包配置
         */
        PackageConfig pc = new PackageConfig();
        // 模块名
        pc.setModuleName(scanner("模块名"));
        //项目包结构 例如com.llf.xxx
        pc.setParent("com.llf");
        //实体类包名
        pc.setEntity("Pojo");
        //Mapper包名
        pc.setMapper("Mapper");
        //Service包名
        pc.setService("Service");
        //去掉service的前缀
        gc.setServiceName("%sService");
        //ServiceImpl包名
        pc.setServiceImpl("ServiceImpl");
        //Mapperxml包名
        pc.setXml("Mapperxml");
        //将包结构设置仍进生成器
        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);
        //实体类字段Lambok
        strategy.setEntityLombokModel(true);
        //Controller自动restful风格
        strategy.setRestControllerStyle(true);
        strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(pc.getModuleName() + "_");
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }

}

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

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

问题注意

为什么JPA不能使用?
JPA提示的方式需要根据Mapper找到实体类, 找到实体类有以下五种方式

  1. 继承mybatis-plus的BaseMapper
  2. Mapper.xml 文件有 resultMap 标签
  3. 在Mapper类上增加注释指定实体类, 例如: @Entity com.xx.xx.UserModel

为什么生成的表名和期望的表名不一致
JPA提示生成代码, 按照以下规则找到表名

  1. 实体类有JPA注解, 例如: @Table(name="t_user")
  2. 实体类有mybais-plus注解, 例如: @TableName("t_user")
  3. 实体类有注释: @TableName com.xx.xx.UserModel
  4. 如果不存在以上规则, 将驼峰转下划线. 例如 UserMode 的表名为: user_model

拓展

如果觉得这样子配置很麻烦,我们可以试试官方新出的MybatisX的插件 它简化了更多配置 可以说是安装即用

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

https://mp.baomidou.com/guide/mybatisx-idea-plugin.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Amazing66/article/details/119081282

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法