快速上手MyBatisPlus(详细)

MyBatisPlus

MyBatisPlus可以节省我们大量工作时间,所有的CRUD代码它都可以自动化完成!

简介

MyBatis、本来就是简化JDBC操作的!

MyBatisPlus,简化MyBatis

官网:https://baomidou.com/

在这里插入图片描述

在这里插入图片描述

一、特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

二、快速入门

使用第三方组件:

  1. 导入对应的依赖
  2. 研究依赖如何配置
  3. 代码如何编写
  4. 提高扩展能力!

步骤

  1. 创建数据库 mybatis-plus

  2. 创建user表

    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, 'test1@baomidou.com'),
    (2, 'Jack', 20, 'test2@baomidou.com'),
    (3, 'Tom', 28, 'test3@baomidou.com'),
    (4, 'Sandy', 21, 'test4@baomidou.com'),
    (5, 'Billie', 24, 'test5@baomidou.com');
    
    -- 真实开发中,version(乐观锁),delete(逻辑删除),gmt_create,gmt_modified
    
  3. 编写项目,初始化项目!使用springboot初始化!

  4. 导入依赖

      <!--数据库驱动 -->
     <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
     </dependency>
     <!--Lombok-->
     <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
     </dependency>
     <!--mybatis-plus-->
     <!--mybatis-plus 是自己开发的,并非官方的-->
     <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
     <dependency>
         <groupId>com.baomidou</groupId>
         <artifactId>mybatis-plus-boot-starter</artifactId>
         <version>3.5.1</version>
     </dependency>
    

    说明:我们使用mybatis-plus可以节省我们大量的代码,尽量不要同时导入mybatis和mybatis-plus!会出错版本差异!

  5. 连接数据库

    #mysql 5 驱动不同 com.mysql.jdbc.Driver
    spring.datasource.username=root
    spring.datasource.password=1127
    spring.datasource.url=jdbc:mysql://localhost:3307/mybatis-plus?useSSL=false&useUnicode=true&characterEncoding=utf-8
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    
    #mysql 8 驱动 com.mysql.cj.jdbc.Driver,需要增加时区的配置 serverTimezone=GMT%2B8
    

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

  6. 使用了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> {
    	//所有的CURD操作都已经编写完成了
    	//不需要像以前的配置一大堆文件了
    }
    
  • 注意:需要在主启动类上去扫描mapper包下的所有接口!

    //扫描mapper文件
    @MapperScan("com.example.mybatis_plus")
    @SpringBootApplication
    public class MybatisPlusApplication {
    	
    	public static void main(String[] args) {
    		SpringApplication.run(MybatisPlusApplication.class, args);
    	}
    	
    }
    
    • 测试

      //继承BaseMapper,所有的方法都来自父类,我们也可以编写自己的扩展方法
      @Autowired
      private UserMapper userMapper;
      
      @Test
      void contextLoads() {
      	//参数是一个Wrapper,条件构造器,这里我们先不用null
      	//查询全部用户
      	List<User> users = userMapper.selectList(null);
      	users.forEach(System.out::println);
      }
      

测试运行,成功查到所有的信息

在这里插入图片描述

小结

通过上述简单的几步,就可以实现 User 表的 CRUD 功能,以往的 XML 文件不再需要

  • 集成MyBatis-Plus非常的简单,只需要引入对应的依赖,并配置 mapper 扫描路径即可

三、配置日志

虽然我们已经实现了基本的CRUD功能,但是相应的sql语句是不可见的,为了看每条sql是怎么执行的,我们必须查看日志;

MyBatis Plus本身集成了log日志功能,我们打开即可

接下来在application.properties中启动MyBatis plus本身日志;我们也可以使用第三方的日志,但是需要导入相应的依赖

#配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

我们再次运行上述的查询全部用户方法,即可查看到所执行sql的相关日志信息

在这里插入图片描述


四、CRUD及其拓展

1. 插入insert & 主键生成策略

//测试插入
@Test
void testInsert() {
   User user = new User();
   user.setName("Azmat");
   user.setAge(22);
   user.setEmail("2271427740@qq.com");
   
   int result = userMapper.insert(user);  //帮我们自动生成id
   System.out.println(result);  
   System.out.println(user); 
}

测试一下,查看日志信息,成功插入数据,且可以看到为我们自动生成了一个ID

在这里插入图片描述

我们并没有设置主键id的值,但是MyBatis Plus自动为我们生成了一个id,这个id是如何生成的?


1. 主键生成策略

系统唯一ID(主键)是我们在设计一个系统的时候常常会遇见的问题,生成ID的方法有很多,适应不同的场景、需求以及性能要求;有些比较复杂的系统甚至会有多个ID生成的策略

分布式系统唯一ID生成方案汇总:https://www.cnblogs.com/haoxinyue/p/5208136.html

MyBatis Plus中,生成主键id的方法是 雪花算法,我们也可以通过@TableId注解设置修改使用其他的生成策略,我们看看该注解的源码

在这里插入图片描述

可以发现这是一个枚举类,其中有五种方式,默认生成ID的方式是ASSIGN_ID,底层也就是通过雪花算法实现的

在这里插入图片描述

  • AUTO:数据库ID自增
  • NONE:未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
  • INPUT:插入前自己设置主键的值
  • ASSIGN_ID:分布式全局唯一ID(长整型类型)
  • ASSIGN_UUID:32位UUID字符串

接下来我们通过@TableID注解指定其他策略试试

2.主键自增AUTO

我们在我们实体类的主键上可以指定所需的方式,这里配置为主键自增方式

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
   
   @TableId(type = IdType.AUTO)
   private Long id;
   private String name;
   private Integer age;
   private String email;
}

同时要在数据库中设置主键id自增,然后保存。否则会报错

在这里插入图片描述

在这里插入图片描述

再次测试一下上述插入方法,成功插入,且新插入user的id实现了自增

在这里插入图片描述

可以发现每次id都+1,成功实现了主键自增功能


3.手动输入INPUT

将主键id上的注解更改为

@TableId(type = IdType.INPUT)

因为我们的数据表设置了主键自增,查看日志信息,发现id为null,因此我们需要手动设置id

//测试插入
@Test
void testInsert() {
   User user = new User();
   user.setId(6L); //手动录入id
   user.setName("alem");
   user.setAge(22);
   user.setEmail("2271427740@qq.com");
   int result = userMapper.insert(user);
   System.out.println(result);
   System.out.println(user);
}

再次测试,成功插入指定id用户

在这里插入图片描述


2. 更新update & 自动填充功能

1. 测试更新

在测试类中新建一个方法,注意updateById()方法传入的参数为User对象

//测试插入
@Test
void testUpdate() {
   User user = new User();
   //通过条件自动自动拼接动态sql
   user.setId(6L);
   user.setName("abdu++");
   int result = userMapper.updateById(user); //参数是一个对象
   System.out.println(result);
}

运行该测试方法,成功更新指定用户的信息

在这里插入图片描述

总结:在MyBatisPlus中,所有的sql都是自动动态配置的(动态sql)

2. 自动填充

数据库写入一些东西时,比如创建时间、修改时间!更新这些字段时,一般都是自动化完成的,不希望自己手动更新

在阿里巴巴开发手册中,所有的数据库表几乎都有两个字段:gmt_creategmt_modified;这两个字段都是自动化更新的

接下来我们来实现一下这两个字段的自动填充

方式一:数据库级别

1. 首先在数据库表user中新增两个字段crate_timeupdate_time

默认值都设置为CURRENT_TIMESTAMPupdata_time字段勾选根据当前时间戳更新,然后保存

在这里插入图片描述

2.同步实体类,新增两个字段

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
   @TableId(type = IdType.INPUT)
   private Long    id;
   private String  name;
   private Integer age;
   private String  email;
   private Date createTime;
   private Date updateTime;
}

3.运行测试

修改一下testUpdate方法后运行测试

//测试插入
@Test
void testUpdate() {
   User user = new User();
   //通过条件自动自动拼接动态sql
   user.setId(6L);
   user.setName("abdu++");
   user.setAge(32);
   int result = userMapper.updateById(user); //参数是一个对象
   System.out.println(result);
}

在这里插入图片描述

方式二:代码级别

1. 首先删除数据表中上述两个字段的默认值以及update_time的更新操作

在这里插入图片描述

2. 我们可以在实体类字段属性上添加注解@TableField实现自动填充,来看看该注解的源码

在这里插入图片描述

其中有个fill属性用于设置字段自动填充策略FieldFill,我们在看看可以设置的策略

在这里插入图片描述

可以看到,FiledFill同样是个枚举类,有四种填充策略,默认是DEFAULT不处理

接下来我们使用该注解在字段上进行设置

  • createTime时填充策略为INSERT:插入填充字段
  • updateTime时填充策略位INSER_UPDATE:插入和更新时填充字段
@Data
@AllArgsConstructor
@NoArgsConstructor
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 createTime;
	@TableField(fill = FieldFill.INSERT_UPDATE)
	private Date updateTime;
}

3. 编写自动填充处理器处理这个注解

在主程序同级目录下新建handler包,其中创建自己的处理器MyMetaObjectHandler类,继承MetaObjectHandler接口,重写其方法

@Slf4j
@Component //放置IOC容器中
public class MyMetaObjectHandler implements MetaObjectHandler {
   //插入时的填充策略
   @Override
   public void insertFill(MetaObject metaObject) {
      log.info("start insert fill.....");
      //在插入时填充`crateTime`和`updateTime`字段
      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);
   }
}

4. 运行测试

首选运行插入方法InsertUser

//测试插入
@Test
void testInsert() {
   User user = new User();
   user.setName("alem");
   user.setAge(22);
   user.setEmail("2271427740@qq.com");
   int result = userMapper.insert(user);
   System.out.println(result);
   System.out.println(user);
}

运行后可以发现新插入的用户两个时间与其他不同,实现了自动填充更新

在这里插入图片描述

然后我们update一下新插入的用户试试

//测试插入
@Test
void testUpdate() {
   User user = new User();
   //通过条件自动自动拼接动态sql
   user.setId(1507204624015212550L);
   user.setName("艾孜");
   user.setAge(22);
   int result = userMapper.updateById(user); //参数是一个对象
   System.out.println(result);
}

运行完可以看到update_time成功更新

在这里插入图片描述

3. 查询select & 分页查询插件

1. 测试查询

1、通过id查询用户

//查询指定用户
@Test
public void selectUserByID() {
   User user = userMapper.selectById(1);
   System.out.println(user);
}

2、查询批量用户

//批量查询用户
@Test
public void selectUserByBatchID() {
	List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 6, 5, 3));//参数为列表集合
	users.forEach(System.out::println);
}

在这里插入图片描述

3、条件查询

//条件查询
@Test
public void selectUserWithCondition() {
   HashMap<String, Object> map = new HashMap<>();
   //自定义查询条件
   map.put("name","alem");
   map.put("age","22");
   List<User> users = userMapper.selectByMap(map);
   users.forEach(System.out::println);
}

在这里插入图片描述

2. 分页查询

在MyBatisPlus内部内置了分页插件,我们稍加配置即可使用

1、配置拦截器组件

在主程序同级目录下新建config包,其中新建MyBatisPlusConfig,其中配置分页插件

同时将扫描包注解@MapperScan("com.zsr.mapper")从我们主程序转移到该配置类,更加规范

@MapperScan("com.example.mybatis_plus")//声明Mapper扫描器
@EnableTransactionManagement
@Configuration // 声明配置类
public class MyBatisPlusConfig {
   //注册bean
   @Bean
   public MybatisPlusInterceptor mybatisPlusInterceptor() {
      //创建插件管理器
      MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
      //添加乐观锁插件
      interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
      //添加分页插件
      interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
      // 返回插件管理器
      return interceptor;
   }
}

2、直接使用page对象进行分页操作

在测试类中测试分页查询

@SpringBootApplication
public class MybatisPlusApplication {
   
   public static void main(String[] args) {
      SpringApplication.run(MybatisPlusApplication.class, args);
   }
}

在这里插入图片描述

成功查出1~3用户,同时可以发现本质还是使用limit进行分页


4. 删除 & 逻辑删除

1. 测试删除
//删除指定id用户
@Test
public void deleteByID() {
   userMapper.deleteById(5);
}

//批量删除
@Test
public void deleteByBatchID() {
   userMapper.deleteBatchIds(Arrays.asList(3,4));
}

//条件删除
@Test
public void deleteByCondition() {
   HashMap<String, Object> map = new HashMap<>();
   map.put("name", "艾孜4");//自定义条件:删除所有name为zsr的
   map.put("id", "1");//自定义条件:删除所有name为zsr的
   userMapper.deleteByMap(map);
}
2. 逻辑删除

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

逻辑删除:数据库中没有移除,而是通过一个变量来让其失效(delete=0 —> delete=1)

1、在数据表中增加一个deleted字段,默认值0

注意:字段不能使数据库中的关键字,如delete

在这里插入图片描述

2、同步pojo实体类

@TableLogic注解标名这是逻辑删除

@TableLogic //逻辑删除
private Integer deleted;

3、配置逻辑删除组件

首先application.properties添加相应的配置

#配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
  • 已删除deleted=1
  • 未删除deleted=0

4、测试

//删除指定5号用户
@Test
public void deleteByID() {
   userMapper.deleteById(5);
}

在这里插入图片描述

可以看到,我们执行的删除方法本质上是更新操作,更新了deleted的值,,刷新user表看看

在这里插入图片描述

可以看到1号用户并没有删除,记录仍在数据库,只是deleted变为1,代表已删除

我们查询所有用户试试

@Test
void contextLoads() {
   //参数是一个wrapper条件构造器,这里先不用,写null
   //查询全部用户
   List<User> users = userMapper.selectList(null);
   users.forEach(System.out::println);
}

在这里插入图片描述

可以看到,查询的时候带了条件deleted=0,即未删除的用户才能被查询到;自动过滤被逻辑删除的字段,所以我们查询不到用户1,因为已经逻辑删除


五、乐观锁插件

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

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

1. 实现方式

当要更新一条记录的时候,希望这条记录没有被别人更新

乐观锁实现方法:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时,set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败
-- A 先查询,获得版本号 version = 1 
update user set name = "zsr", version = version + 1 
where id = 2 and version = 1

-- B 如果此时B线程抢先完成,这个时候 version = 2,会导致 A 修改失败! 
update user set name = "zsr", version = version + 1 
where id = 2 and version = 1

2. 测试乐观锁插件

1、添加version字段

首先给数据库表添加一个version字段,设置默认值为1

在这里插入图片描述

查看是否添加成功

在这里插入图片描述

2、同步实体类

注意添加@version注解

@Version //代表这是一个乐观锁
private Integer version;

3、注册乐观锁组件

在主程序同级目录下新建config包,其中新建MyBatisPlusConfig注册乐观锁插件

@EnableTransactionManagement
@Configuration
public class MyBatisPlusConfig {
   //注册乐观锁插件
   @Bean
   public MybatisPlusInterceptor mybatisPlusInterceptor() {
      MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
      interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
      return interceptor;
   }  
}

4、测试

测试一下,分别测试乐观锁成功和失败的两种情况

1、首先测试单线程对用户进行修改的情况

//单线程测试乐观锁成功
@Test
public void TestOptimisticLockerInnerInterceptor_success() {
   //获取用户
   User user = userMapper.selectById(1);
   //修改用户信息
   user.setName("Nizamat");
   user.setEmail("aize@qq.com");
   //执行更新操作
   userMapper.updateById(user);
}

运行测试一下,修改成功信息,查看打印的日志

在这里插入图片描述

可以看到,第一次的查询和第二次的更新操作的sql语句都附加了version信息,第一次查出来version为1,更新操作时,version+1更改为2,这就是乐观锁的作用,修改成功

在这里插入图片描述

2、再测试两个线程都对用户进行修改的情况

//测试多线程修改
@Test
public void TestOptimisticLockerInnerInterceptor_fail() {
   //线程1,设置了值但未修改
   User user1 = userMapper.selectById(1);
   user1.setName("艾孜1");
   user1.setEmail("6379@qq.com");
   
   //线程2,设置了值且更新
   User user2 = userMapper.selectById(1);
   user2.setName("艾孜2");
   user2.setEmail("63792@qq.com");
   userMapper.updateById(user2);
   
   //线程1进行更新:如果没有乐观锁就会覆盖线程2设置的值
   userMapper.updateById(user1);
}

运行测试一下,查看日志信息,可以看到线程2的更新操作成功了,线程1并未成功,这是因为线程2更新前,version的值为2,更新后变为3,但是线程1最后的更新操作的附加条件version仍未2,与当下version不同,所以更新失败

在这里插入图片描述

同时可以查看user表,最终结果是线程2修改的结果

在这里插入图片描述


六、性能分析插件

开发过程中,会遇到一些慢sql,我们通常需要将其提取出来并进行相应的优化,优化查询效率;

  • 作用:用于输出每条SQL语句执行的时间,如果sql语句的时间超过我们指定的时间,就可以停止运行

该插件 3.2.0 以上版本移除推荐使用第三方扩展 执行 SQL 分析打印 功能


七、条件构造器

在这里插入图片描述

1. 条件查询

一、简单条件运算符

eq:等于 =

ne:不等于 <>

gt:大于 >

ge:大于等于 >=

lt:小于 <

le:小于等于 <=

二、逻辑运算符

or:拼接or
and:
nest
三、模糊查询

between:between 值1 and 值2
notbetween:notbetween 值1 and 值2
like:like ‘%值%’
not like:notlike ‘%值%’
likeLeft:like ‘%值’
likeRight:like ‘值%’
isNull:字段为空
isNotNull:字段不为空
in:字段 in(value1,value2 …)
notIn:字段 notIn(value1,value2 …)

1、查询name不为空,邮箱不为空且年龄>=20的用户

@Test
void test1() {
   //查询name不为空,邮箱不为空、年龄>=22的用户
   QueryWrapper<User> wrapper = new QueryWrapper<>();
   wrapper.isNotNull("name")
         .isNotNull("email")
         .ge("age", 22);
   userMapper.selectList(wrapper).forEach(System.out::println);
}

运行测试,查看输入信息,可以发现附加了我们所需的条件语句

在这里插入图片描述

2、查询名字为Jack

@Test
void test2() {
   //查询名字为Jack
   QueryWrapper<User> wrapper = new QueryWrapper<>();
   wrapper.eq("name","Jack");
   User user = userMapper.selectOne(wrapper);  //查询一个数据,出现多个结果使用List或者Map
   System.out.println(user); 
}

3、查询年龄小于20或大于25的用户

//查询年龄小于20或大于25的用户
@Test
public void test3() {
   QueryWrapper<User> wrapper = new QueryWrapper<>();
   //链式编程
   wrapper.lt("age", 18).or().gt("age", 22);
   Long count = userMapper.selectCount(wrapper);
   System.out.println(count);
}

在这里插入图片描述

4、查询年龄介于20~30之间的用户

//查询年龄介于20~30之间的用户
@Test
public void test4() {
   QueryWrapper<User> wrapper = new QueryWrapper<>();
   //链式编程
   wrapper.between("age", 20, 30);
   userMapper.selectCount(wrapper);//返回结果数
}

在这里插入图片描述

5、模糊查询、查询名字中不包含J的,且邮箱以t开头的

//查询名字中不包含J的,且邮箱以t开头的
@Test
public void test5() {
   QueryWrapper<User> wrapper = new QueryWrapper<>();
   //链式编程
   wrapper
         .notLike("name", "J")
         .likeRight("email", "t");//相当于右边加一个百分号:t%
   List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
   maps.forEach(System.out::println);
}

在这里插入图片描述

2. 子查询

  • inSql:字段 in(sql语句)
  • notInSql:字段 notIn(sql语句)
//子查询
@Test
public void test6() {
   QueryWrapper<User> wrapper = new QueryWrapper<>();
   //链式编程
   wrapper.inSql("id", "select id from user where id<3");
   List<Object> objects = userMapper.selectObjs(wrapper);
   objects.forEach(System.out::println);
}

在这里插入图片描述

3. 分组查询

  • groupBy:group by 字段,…
  • having:having(sql语句)
//根据update_time分组查询
@Test
public void test8() {
   QueryWrapper<User> wrapper = new QueryWrapper<>();
   //链式编程
   wrapper.select("count(*)","update_time")
         .groupBy("update_time");
   userMapper.selectObjs(wrapper);
}

在这里插入图片描述

4. 排序查询

  • orderByAsc:order by 字段,… asc
  • orderByDesc:order by 字段,… desc

1、按id降序排序查询

//按id降序排序查询
@Test
public void test7() {
   QueryWrapper<User> wrapper = new QueryWrapper<>();
   wrapper.orderByDesc("id");//id降序排序查询
   //wrapper.orderByAsc("id");//id降序升序查询
   userMapper.selectObjs(wrapper);
}

在这里插入图片描述


八、代码自动生成器

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

1、添加依赖
<!--代码生成器-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.2.0</version>
</dependency>
2.编写自动生成代码
package com.example.createcode;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
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.Scanner;

// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中
public class Generator {
    
    /**
     * <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.isNotEmpty(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "!");
    }
    
    public static void main(String[] args) {
        //需要构建一个代码自动生成器对象
        AutoGenerator mpg = new AutoGenerator();
    
        // 1.全局配置
        GlobalConfig gc          = new GlobalConfig();
        String       projectPath = System.getProperty("user.dir");//获取当前项目路径
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("Azmat");//设置作者名
        gc.setOpen(false); //设置是否打开资源管理器
        gc.setFileOverride(true);//是否覆盖原来生成的代码
        gc.setBaseResultMap(true); // xml resultmap
        gc.setBaseColumnList(true); // xml columlist
        gc.setServiceName("%sService"); //去Service的I前缀
        gc.setIdType(IdType.ID_WORKER);//设置主键生成策略
        gc.setDateType(DateType.ONLY_DATE);//设置日期类型
        gc.setSwagger2(true); //设置自动配置swagger文档,实体属性Swagger2注解
        //将全局配置装入自动代码生成器
        mpg.setGlobalConfig(gc);
        
        //2.数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3307/mybatis-plus?&characterEncoding=utf8&useSSL=false&serverTimezone=UTC");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("密码");
        mpg.setDataSource(dsc);
    
        //3.包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("blog");//设置模块名
        pc.setParent("com.example");//设置放置的包名
        pc.setController("controller");//controller层包名
        pc.setEntity("pojo" );//pojo层包名
        pc.setMapper("mapper");//mapper层包名
        pc.setService("service" );//service层包名
        pc.setServiceImpl("service.impl");//实现类
        //将包配置装入自动代码生成器
        mpg.setPackageInfo(pc);
    
        //4.策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);//设置包命名的规则:下划线转驼峰命名
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//设置数据库字段命名规则
        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);//修改时间
		//ArrayList<TableFill> tableFills = new ArrayList<>();//自动填充策略集
		//tableFills.add(gmtCreate);
		//tableFills.add(gmtModified);
		//strategy.setTableFillList(tableFills);//设置自动填充策略
    
        //乐观锁
		//strategy.setVersionFieldName("version");
        strategy.setRestControllerStyle(true);//开启restful驼峰命名格式
    
        // 写于父类中的公共字段
        strategy.setSuperEntityColumns("id");
        strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));//设置要映射的数据表名
        strategy.setControllerMappingHyphenStyle(true);//设置请求链接格式,例如localhost:8080/hello_id_2
        strategy.setTablePrefix(pc.getModuleName() + "_");
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
    
        //执行代码构造器
        mpg.execute();
    }    
}
3.测试

表名,多个表可以英文逗号分割

在这里插入图片描述

以下生成的代码

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值