欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

一天入门MyBatisPlus

程序员文章站 2022-04-15 19:12:16
1、简介官网地址:https://mp.baomidou.com/MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。特性无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器...

1、简介

官网地址:https://mp.baomidou.com/

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

一天入门MyBatisPlus

特性

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

支持数据库

  • mysql 、 mariadb 、 oracle 、 db2 、 h2 、 hsql 、 sqlite 、 postgresql 、 sqlserver 、 presto
  • 达梦数据库 、 虚谷数据库 、 人大金仓数据库

2、快速搭建MyBatis-Plus

2.1 首先去创建一个数据库

drop table if exists user;
create table user(
id int primary key auto_increment, -- 主键id
name VARCHAR(255) not null, -- 姓名
age int not null, -- 年龄
email VARCHAR(50) -- 邮箱
);
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');
select * from user;

2.2创建springboot项目

2.2、1 添加依赖

向 pom.xml 中 添加依赖

<dependencies>
    <!--  druid-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.21</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.2.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

2.2、2 配置application.yml

spring:
  datasource:
    username: root
    password: ******
    url: jdbc:mysql://localhost:3306/mbp?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.NonRegisteringDriver
    type: com.alibaba.druid.pool.DruidDataSource

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

2.2、3 编写实体类

@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

2.2、4 编写mapper层

@Mapper
@Component
public interface UserMapper  extends BaseMapper<User> {
}

2.2、4 开始测试

@SpringBootTest
class DemoApplicationTests {

    @Autowired
    private  UserMapper userMapper;

    @Test
    void contextLoads() {
    }
    @Test
    public void testSelect() {
        System.out.println(("----- selectAll method test ------"));
        List<User> userList = userMapper.selectList(null);
        userList.forEach(System.out::println);
    }

}

3、CRUD

3.1 添加

 @Test
    public void add() {
        User user = new User();
        user.setAge(20);
        user.setEmail("11111@qq.com");
        user.setName("扬州炒饭");
        userMapper.insert(user);
        System.out.println(user);
    }

这块id mybatis-plus会自动生成

注意:使用mysql数据库会添加失败

由于mybatis-plus会自动插入一个id到实体对象, 不管你是否对id设置值都会向实体类中添加一个long类型的值, 所以有时候导致一些意外的情况发生

所以这块建议在 实体类上加上主键策略

 //对应数据库主键id IdType.AUTO主键自增 数据库中也必须设置自增
    @TableId(type = IdType.ID_WORKER)

3.1 .1主键生成策略

     /**
     * 数据库ID自增
     */
    AUTO(0),
    /**
     * 该类型为未设置主键类型(将跟随全局)
     */
    NONE(1),
    /**
     * 用户输入ID
     * <p>该类型可以通过自己注册自动填充插件进行填充</p>
     */
    INPUT(2),

    /* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
    /**
     * 全局唯一ID (idWorker)
     */
    ID_WORKER(3),
    /**
     * 全局唯一ID (UUID)
     */
    UUID(4),
    /**
     * 字符串全局唯一ID (idWorker 的字符串表示)
     */
    ID_WORKER_STR(5);

  

3.2 更新

@Test
    public void update() {
        User user = new User();
        //通过条件自动拼接动态sql
        user.setId(6);
        user.setAge(20);
        user.setEmail("11111@qq.com");
        user.setName("扬州炒饭好吃吗");
        userMapper.updateById(user);
        System.out.println(user);
    }

3.3 查询

批量查询:

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

    }

条件查询 map:

 //按条件查询  map
    @Test
    public void selectBy(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("version",1);
        map.put("age",18);
        List<User> userList = userMapper.selectByMap(map);
        userList.forEach(System.out::print);

    }

3.4 分页查询

  • 配置拦截器

     @Bean
        public PaginationInterceptor paginationInterceptor() {
            PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
            // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
            // paginationInterceptor.setOverflow(false);
            // 设置最大单页限制数量,默认 500 条,-1 不受限制
            // paginationInterceptor.setLimit(500);
            // 开启 count 的 join 优化,只针对部分 left join
            paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
            return paginationInterceptor;
        }
    

3.5 自动填充

创建时间,修改时间

gmt_create,gmt_modified

1.给数据库添加字段

gmt_create datetime,  -- 创建时间
gmt_modified datetime -- 修改时间

2.给实体类添加字段 并添加注解

	@TableField(fill = FieldFill.INSERT)
    private String gmtCreate;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private String gmtModified;

3.添加处理器去 处理注解

@Slf4j
@Component
public class MyBatisPlusFill implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        this.setFieldValByName("gmtCreate", DateUtil.getTime(), metaObject);
        this.setFieldValByName("gmtModified", DateUtil.getTime(), metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        this.setFieldValByName("gmtModified", DateUtil.getTime(), metaObject);
    }
}

再去做测试就ok了

这里遇到的坑,官网最新的方法时间添加不上去,最后用了旧的方法

3.6 删除

 //删除
    @Test
    public void delete(){
        userMapper.deleteById(6);
    }
    //批量删除
    @Test
    public void deleteBatchIds(){
        userMapper.deleteBatchIds(Arrays.asList(1,2,3,4,5,6));
    }
    //map删除
    @Test
    public void deleteMap(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("email","11111@qq.com");
        userMapper.deleteByMap(map);
    }

3.7 逻辑删除

在数据库中没有删除,通过字段使它查不到 好比回收站

3.7.1添加sql字段

deleted int DEFAULT '0' -- 逻辑删除

3.7.2 实体类加注解

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

3.7.3 yml添加配置

global-config:
    db-config:
      logic-delete-field: flag  # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

删除其实执行的是

UPDATE user SET deleted=1 WHERE id=? AND deleted=0 

查询的时候为添加上 where deleted=0 所以就查不出来了

4、乐观锁

  • 乐观锁:不会使用数据库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。
  • 悲观锁:这是一种对数据的修改抱有悲观态度的并发控制方式。我们一般认为数据被并发修改的概率比较大,所以需要在修改之前先加锁。

乐观锁实现方式

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

测试

3.1首先给数据库添加字段

version int DEFAULT '1' -- 乐观锁

3.2 添加实体类

  @Version //乐观锁
    private int version;

3.3 注册组件

@MapperScan("com.chen.mapper")
@Configuration
public class MyBatisPlusConfig {

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

3.4测试

//测试乐观锁
    @Test
    public void testOptimisticLocker(){
        User user = userMapper.selectById(1);
        user.setName("炒饭");
        user.setEmail("1111@Qq.com");
        userMapper.updateById(user);
    }
    //测试乐观锁 多线程
    @Test
    public void test1OptimisticLocker(){
        //线程1
        User user = userMapper.selectById(1);
        user.setName("炒饭");
        user.setEmail("1111@Qq.com");

        // 线程2 线程插队
        User user1 = userMapper.selectById(1);
        user1.setName("小炒饭");
        user1.setEmail("2221@Qq.com");

        userMapper.updateById(user1);
        userMapper.updateById(user);
        //如果没有乐观锁,线程1 就会覆盖线程2 的值
    }

5、执行 SQL 分析打印

这块的话 我是用的druid 所以就不写了

需要的话直接官网看吧

6、条件构造器

package com.chen;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chen.mapper.UserMapper;
import com.chen.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

/**
 * @author blackcats
 * @date 2020/7/26 19:53
 * 代码太难了
 */
@SpringBootTest
public class WrapperTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void test1(){
        //查询name不为空 并且age >= 20
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.isNotNull("name")
                .ge("age",20);
        userMapper.selectList(wrapper);
    }

    @Test
    public void test2(){
        //查询name是 Tom 的
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name","Tom");
        userMapper.selectOne(wrapper);//一条数据 使用 selectOne
    }
    @Test
    public void test3(){
        //查询年龄在 21 到 28的
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("age",21,28); //包含21和28
        userMapper.selectCount(wrapper);//查询结果数
    }
    //模糊查询
    @Test
    public void test4(){
        //查询名字中带  a 的数据 并且邮箱以a开头
        //左和右
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.like("name","a").likeRight("email","a");

        //查询名字中不带  e 的数据
        //QueryWrapper<User> wrapper = new QueryWrapper<>();
        //wrapper.notLike("name","e");
        userMapper.selectList(wrapper);//查询结果数
    }

    @Test
    public void test5(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //age在子查询中查出
        wrapper.inSql("age","select age  from user where age>18");
        List<Object> objects = userMapper.selectObjs(wrapper);
        objects.forEach(System.out::print);

    }
    @Test
    public void test6(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //通过id降序排序
        wrapper.orderByDesc("id");
        List<User> userList = userMapper.selectList(wrapper);
        userList.forEach(System.out::print);

    }
    @Test
    public void test7(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //查询名字中有a 并且年龄大于20 的
        wrapper.and(i -> i.like("name", "a").gt("age", "20"));
        List<User> userList = userMapper.selectList(wrapper);
        userList.forEach(System.out::print);

    }
}

7、代码生成器

package com.chen;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import java.util.ArrayList;

/**
 * @author blackcats
 * @date 2020/7/26 20:37
 * 代码太难了
 */
public class CommunityCode {
    public static void main(String[] args) {
        //new出代码生成器对象
        AutoGenerator mbp = new AutoGenerator();

        // 全局配置  导入generator下的包
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath+"/src/main/java");
        gc.setAuthor("扬州炒饭"); //作者名字注释
        gc.setOpen(false); //不打开资源管理器
        gc.setFileOverride(false);// 是否覆盖
        gc.setServiceName("%sService");//去掉service i 前缀
        gc.setIdType(IdType.AUTO); //生成主键策略
        mbp.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/community?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8");
        // dsc.setSchemaName("public");
        dsc.setDriverName("com.mysql.cj.jdbc.NonRegisteringDriver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        mbp.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("blog");
        pc.setParent("chen");
        pc.setController("controller");
        pc.setEntity("pojo");
        pc.setService("service");
        pc.setMapper("mapper");

        mbp.setPackageInfo(pc);
        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("user","question","comments","type"); //重点 一般主要就改这些地方 设置映射表名
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);// 自动lombok
        //自动填充
        TableFill gmt_create = new TableFill("gmt_create", FieldFill.INSERT);
        TableFill gmt_modified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);
        ArrayList<TableFill> list = new ArrayList<>();
        list.add(gmt_create);
        list.add(gmt_modified);
        strategy.setTableFillList(list);
        strategy.setLogicDeleteFieldName("deleted"); //设置逻辑删除字段
        //乐观锁
        strategy.setVersionFieldName("version");
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);
        mbp.setStrategy(strategy);


        mbp.execute();
    }
}

总结

这个东西用着是很香,可是我不建议经常使用它

项目已经上传码云,点击跳转

本文地址:https://blog.csdn.net/qq_35800844/article/details/107599780