当前位置: 移动技术网 > IT编程>开发语言>Java > 一天入门MyBatisPlus

一天入门MyBatisPlus

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

1、简介

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

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

在这里插入图片描述

特性

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

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网