一篇搞定MyBatis Plus

什么是MyBatis Plus

国产的开源框架,基于 MyBatis

核心功能就是简化 MyBatis 的开发,提高效率

有了他甚至不用自己写sql语句了

快速上手

  • 创建Spring Boot项目,并且在pom.xml中导入MyBatis Plus的依赖

     <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.3.1</version>
            </dependency>
    
  • 配置数据建库application.yml

    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
        username: root
        password: xxxxx
    
    
  • 根据自己测试的数据库创建实体类,用到了Lombok

    import lombok.Data;
    
    @Data
    public class User {
        private int id;
        private String name;
        private String pwd;
    }
    
    
  • 根据实体类写一个mapper,继承BaseMapper接口,泛型写的是实体类的类型

    //只需要创建,不需要实现,mybatis中要去配置xml文件写sql语句
    //mybatisPlus直接继承BaseMapper接口就行,泛型是这个mapper对应的实体类
    public interface UserMapper extends BaseMapper<User> {
        
    }
    
    
  • 启动类需要添加 @MapperScan(“mapper所在的包”),否则无法加载 Mppaer bean

    @SpringBootApplication
    @MapperScan("com.ori.mybatisplus.mapper")
    public class MybatisplusApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(MybatisplusApplication.class, args);
        }
    
    }
    
  • 接下来就可以测试了,测试一个不加条件的获取表中所有内容

    @SpringBootTest
    class UserMapperTest {
    
        @Autowired
        private UserMapper mapper;//mapper显示红线不影响运行
    
        @Test
        void test(){
            mapper.selectList(null).forEach(System.out::println);
           
            }
        }
    
  • 启动后获得输出,代表快速上手成功!
    在这里插入图片描述

  • 默认看不到sql语句,但是可以在yml中配置,然后再输出

    mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    
  • 我们可以看到MyBatis Plus会创建sqlSession去链接JDBC然后去执行sql语句,而sql语句是自动生成好的,并且自动关联到了相应的表

在这里插入图片描述

常用注解

@TableName

映射数据库的表名,上面快速上手是因为我们的表名和实体类名字一致所以可以不加,如果不一致,则可通过该注解进行映射,比如:

@Data
@TableName(value = "user")
public class Account {
    private Integer id;
    private String name;
    private String pwd;
}

@TableId

设置主键映射,value 映射主键字段名

type 设置主键类型,主键的生成策略,见下表

描述
AUTO数据库自增
NONEMP set 主键,雪花算法实现
INPUT需要开发者手动赋值
ASSIGN_IDMP 分配 ID,可以使用Long、Integer、String类型
ASSIGN_UUID分配 UUID,Strinig类型

AUTO 默认就是数据库自增,开发者无需赋值。

INPUT 如果开发者没有手动赋值,则数据库通过自增的方式给主键赋值,如果开发者手动赋值,则存入该值。

ASSIGN_ID MP 自动赋值,雪花算法。

ASSIGN_UUID 主键的数据类型必须是 String,自动生成 UUID 进行赋值

@TableField

映射非主键字段,value 映射字段名

exist 表示是否为数据库字段 false,如果实体类中的成员变量在数据库中没有对应的字段,比如User中没有gender这一项,则可以使用 exist,在VO、DTO中常用

select 表示是否查询该字段

fill 表示是否自动填充,将对象存入数据库的时候,由 MyBatis Plus 自动给某些字段赋值,create_time、update_time

  1. 给表添加 create_time、update_time 字段

  2. 实体类中添加成员变量

@Data
@TableName(value = "user")
public class User {
    @TableId
    private String id;
    @TableField(value = "name",select = false)
    private String title;
    private Integer age;
    @TableField(exist = false)
    private String gender;
      //.INSERT表示插入时刷新
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
      //.INSERT_UPDATE表示插入和更新时时刷新
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
}
  1. 给fill创建自动填充处理器,实现MetaObjectHandler接口

    @Component//交给springboot接管,放到Ioc中
    class FillTimeHandler implements MetaObjectHandler {
        @Override
        public void insertFill(MetaObject metaObject) {
            //即给metaObject对象的createTime 赋值 new Date()
            this.setFieldValByName("create_time",new Date(),metaObject);
            this.setFieldValByName("update_time",new Date(),metaObject);
        }
    
        @Override
        public void updateFill(MetaObject metaObject) {
            this.setFieldValByName("update_time",new Date(),metaObject);
    
        }
    }
    
  2. 然后分别执行插入和更新测试

       @Test
        void save(){
            User user = new User();
            user.setId(7);
            user.setName("李小四");
            user.setPwd("12345");
            mapper.insert(user);
        }
    
        @Test
        void update(){
            User user = mapper.selectById(7);
            user.setName("李小小四");
            mapper.updateById(user);
    
        }
    

    结果成功

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

@Version

标记乐观锁,通过 version 字段来保证数据的安全性,当修改数据的时候,会以 version 作为条件,当条件成立的时候才会修改成功。

version = 2

线程 1:update … set version = 2 where version = 1

线程2 :update … set version = 2 where version = 1

1、数据库表添加 version 字段,默认值为 1

2、实体类添加 version 成员变量,并且添加 @Version

@Data
@TableName(value = "user")
public class User {
    @TableId
    private String id;
    @TableField(value = "name",select = false)
    private String title;
    private Integer age;
    @TableField(exist = false)
    private String gender;
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    //加一个version字段
    @Version
    private Integer version;
}

3、注册配置类

package com.ori.mybatisplus.config;
@Configuration
public class MyBatisPlusConfig {
    
    @Bean//返回一个OptimisticLockerInterceptor乐观锁拦截器并注入到Ioc中
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }
    
}

更新前:

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

更新后:

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

双线程情况下,如果同时运行两个语句,则只有先调的会成功修改

@EnumValue

1、通用枚举类注解,将数据库字段映射成实体类的枚举类型成员变量

package com.ori.mybatisplus.enums;

public enum StatusEnum {
    WORK(1,"上班"),
    REST(0,"休息");

    StatusEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    @EnumValue
    private Integer code;
    private String msg;
}
package com.ori.mybatisplus.entity;

@Data
@TableName(value = "user")
public class User {
    @TableId
    private String id;
    @TableField(value = "name",select = false)
    private String title;
    private Integer age;
    @TableField(exist = false)
    private String gender;
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    @Version
    private Integer version;
    private StatusEnum status;
}

application.yml

type-enums-package: 
  com.southwind.mybatisplus.enums

进行查询,可以发现成功映射

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

2、实现接口

package com.ori.mybatisplus.enums;

public enum AgeEnum implements IEnum<Integer> {
    ONE(1,"一岁"),
    TWO(2,"两岁"),
    THREE(3,"三岁");

    private Integer code;
    private String msg;

    AgeEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    @Override
    public Integer getValue() {
        return this.code;
    }
}

@TableLogic

映射逻辑删除

1、数据表添加 deleted 字段

2、实体类添加注解

package com.ori.mybatisplus.entity;
@Data
@TableName(value = "user")
public class User {
    @TableId
    private String id;
    @TableField(value = "name",select = false)
    private String title;
    private AgeEnum age;
    @TableField(exist = false)
    private String gender;
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    @Version
    private Integer version;
    @TableField(value = "status")
    private StatusEnum statusEnum;
    @TableLogic
    private Integer deleted;
}

3、application.yml 添加配置

global-config:
  db-config:
    logic-not-delete-value: 0
    logic-delete-value: 1

这样执行删除语句后

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

数据不会实际删除,而是deleted变成1,再去查询时,就不会查到这个语句,因为mybatis plus在查询语句中会判断deleted是否为0


CRUD

查询

  • selectList(条件)
//mapper.selectList(null);
QueryWrapper wrapper = new QueryWrapper();

//多条件查询,比如allEq,满足两个条件
//        Map<String,Object> map = new HashMap<>();
//        map.put("name","小红");
//        map.put("age",3);
//        wrapper.allEq(map);

//大于
//        wrapper.gt("age",2);

//不等于
//        wrapper.ne("name","小红");

//大于等于
//        wrapper.ge("age",2);

//like '%小'
//        wrapper.likeLeft("name","小");
//like '小%'
//        wrapper.likeRight("name","小");

//inSQL联合查询
//        wrapper.inSql("id","select id from user where id < 10");
//        wrapper.inSql("age","select age from user where age > 3");

//降序查询
//        wrapper.orderByDesc("age");
//升序查询然后加条件
//        wrapper.orderByAsc("age");
//        wrapper.having("id > 8");

//不管什么条件,只要将wrapper放入就行
mapper.selectList(wrapper).forEach(System.out::println);
  • 其他常用查询方式
//要找7,8,9的id的数据
//        mapper.selectBatchIds(Arrays.asList(7,8,9)).forEach(System.out::println);

//Map 只能做等值判断,逻辑判断需要使用 Wrapper 来处理
//        Map<String,Object> map = new HashMap<>();
//        map.put("id",7);
//        mapper.selectByMap(map).forEach(System.out::println);

//输出查询的数据条数
//		 QueryWrapper wrapper = new QueryWrapper();
//       wrapper.eq("id",7);
//       System.out.println(mapper.selectCount(wrapper));

//将查询的结果集封装到Map中
//        mapper.selectMaps(wrapper).forEach(System.out::println);
//        System.out.println("-------------------");
//        mapper.selectList(wrapper).forEach(System.out::println);

//分页查询(首先要去config里加一个PageinationInterceptor的返回,类似前面的乐观锁)
//        Page<User> page = new Page<>(2,2);
//        Page<User> result = mapper.selectPage(page,null);
//        System.out.println(result.getSize());
//        System.out.println(result.getTotal());
//        result.getRecords().forEach(System.out::println);

//        Page<Map<String,Object>> page = new Page<>(1,2);
//        mapper.selectMapsPage(page,null).getRecords().forEach(System.out::println);

//获取主键
//        mapper.selectObjs(null).forEach(System.out::println);

//获取一条,但是必须满足条件的只能有一条
//System.out.println(mapper.selectOne(wrapper));

自定义 SQL(多表关联查询只能用自定义SQL)

package com.ori.mybatisplus.entity;

@Data
public class ProductVO {
    private Integer category;
    private Integer count;
    private String description;
    private Integer userId;
    private String userName;
}
package com.ori.mybatisplus.mapper;

public interface UserMapper extends BaseMapper<User> {
    @Select("select p.*,u.name userName from product p,user u where p.user_id = u.id and u.id = #{id}")
    List<ProductVO> productList(Integer id);
}

然后直接在测试中的mapper.productList(Integer id)调用就好

添加

User user = new User();
user.setTitle("小明");
user.setAge(22);
mapper.insert(user);

删除

//       mapper.deleteById(1);

//        mapper.deleteBatchIds(Arrays.asList(7,8));
//        QueryWrapper wrapper = new QueryWrapper();
//        wrapper.eq("age",14);
//        mapper.delete(wrapper);

//		  Map<String,Object> map = new HashMap<>();
//		  map.put("id",10);//等值判断
//		  mapper.deleteByMap(map);

修改

//先查询再删除
//        User user = mapper.selectById(7);
//        mapper.updateById(user);

//根据条件删除
//User user = mapper.selectById(1);
//user.setTitle("小红");
//QueryWrapper wrapper = new QueryWrapper();
//wrapper.eq("age",22);
//mapper.update(user,wrapper);

MyBatisPlus 自动生成

根据数据表自动生成实体类、Mapper、Service、ServiceImpl、Controller

1、pom.xml 导入 MyBatis Plus Generator

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.3.1.tmp</version>
</dependency>

<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity</artifactId>
    <version>1.7</version>
</dependency>

其中第二项是生成模板,支持:Velocity(默认)、Freemarker、Beetl

2、编写一个启动类

package com.ori;

public class Main {
    public static void main(String[] args) {

        //创建一个autoGenerator对象
        AutoGenerator autoGenerator = new AutoGenerator();

        //创建一个dataSourceConfig对象
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        //配置数据库类型
        dataSourceConfig.setDbType(DbType.MYSQL);
        //数据源等设置
        dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC");
        dataSourceConfig.setUsername("root");
        dataSourceConfig.setPassword("root");
        dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
        //设置完后丢入autoGenerator中
        autoGenerator.setDataSource(dataSourceConfig);

        //进行全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setOutputDir(System.getProperty("user.dir")+"/src/main/java");
        globalConfig.setOpen(false);//设置false表示创建后不会自动打开文件夹
        globalConfig.setAuthor("ori");//不写的话默认是计算机名
        //设置完后丢入autoGenerator中
        autoGenerator.setGlobalConfig(globalConfig);

        //设置输出包信息
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setParent("com.ori");
        packageConfig.setModuleName("generator");//表示在com.ori下创建一个generator包
        packageConfig.setController("controller");
        packageConfig.setService("service");
        packageConfig.setServiceImpl("serviceImpl");
        packageConfig.setMapper("mapper");
        packageConfig.setEntity("entity");
        //设置完后丢入autoGenerator中
        autoGenerator.setPackageInfo(packageConfig);

        //配置策略
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setEntityLombokModel(true);//给实体类自动加上@lombok
        strategyConfig.setNaming(NamingStrategy.underline_to_camel);//下划线转驼峰命名
        strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);//下划线转驼峰命名,这两段一般一起使用
        strategyConfig.setInclude("user");//选定数据库中要生成的表,可用逗号隔开填入多个
        autoGenerator.setStrategy(strategyConfig);

        //启动
        autoGenerator.execute();

    }
}

执行后生成相应的文件
在这里插入图片描述
例如实体类如下图,也成功将下划线转换为了驼峰命名法
在这里插入图片描述
controller也创建好了,有了代码生成器,我们只需要专注于写接口的逻辑就好,非常方便
在这里插入图片描述

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值