Mybatis-plus简介

不在需要手写mapper和mapper.xml文件,只需要创建mapper接口,集成baseMappoer即可

Quick Start

  • 创建数据库环境
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)
);
DELETE FROM user;

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');
  • 新建SpringBoot项目,选择Spring Web,Lombok依赖
  • 添加依赖
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.2</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
  • 更改配置文件
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/demo?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
  application:
    name: plus-test

server:
  port: 8090
  • 创建pojo类和mapper方法,mapper方法继承BaseMapper<表对象>,添加持久层依赖@Repository
  • 测试类调用mapper中的方法

配置日志输出

添加配置文件

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

主键策略

主键自动生成

可以在pojo类中主键字段上加入注解 @TableId(type = IdType.AUTO)

package com.baomidou.mybatisplus.annotation;

public enum IdType {
    AUTO(0),		//在原来的基础上自动加一,前提是表字段为自增
    NONE(1),		//3.4.2版本默认的,id为0,如果数据库中已经存在0,则报错
    INPUT(2),		//必须要输入主键
    ASSIGN_ID(3),
    ASSIGN_UUID(4),
    @Deprecated
    ID_WORKER(3),	//全局唯一ID
    @Deprecated
    ID_WORKER_STR(3),	//ID_word的字符串表示法
    @Deprecated
    UUID(4);		//全局唯一ID uuid
    private final int key;

    private IdType(int key) {
        this.key = key;
    }

    public int getKey() {
        return this.key;
    }
}

表中新建表(create_time)和修改表字段(update_time)更新

数据库实现

image-20220803102929663

代码实现

  • 先删除之前数据库中的触发器和默认值,只创建列名

  • 在字段上声明注解

@TableField(fill = FieldFill.INSERT)
private Date create_time;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date update_time;
  • 创建MyMetaObjectHandler对象实现MetaObjectHandler接口
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert !");
        this.setFieldValByName("create_time",new Date(),metaObject);
        this.setFieldValByName("update_time",new Date(),metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update !");
        this.setFieldValByName("update_time",new Date(),metaObject);
    }
}

乐观锁

  • 表中加入version字段 ,int类型,默认值为1

  • 在pojo类中version上声明注解@Version

  • 在config下创建配置类

@MapperScan("com.my.mapper")
@EnableTransactionManagement
@Configuration
public class MybatisPlusConfig {
    //注册乐观锁插件
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}
  • 测试执行结果
@Test
void t3(){
    Userinfo userinfo = userMapper.selectById(2);
    userinfo.setName("aaa");

    Userinfo userinfo2 = userMapper.selectById(2);
    userinfo2.setName("bbb");
    userMapper.updateById(userinfo2);

    userMapper.updateById(userinfo);
}

分页锁插件

  • 在配置类中注册bean对象
//分页操作插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor2() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
    return interceptor;
}
  • 测试使用
@Test
void t4(){
    Page<Userinfo> objectPage = new Page<>(1,3);
    userMapper.selectPage(objectPage,null);
    objectPage.getRecords().forEach(System.out::println);
}

逻辑删除

  • 表中添加字段deleted,int类型,默认为1
  • pojo类中填加字段,注解@TableLogic
  • 测试使用(原先的删除变成的update,查找自动添加后置条件(deleted = 0)

image-20220803145733467

性能分析插件

mybatis-plus3.2版本移除了性能分析插件

之前版本的使用

  • 添加配置类中的组件
//SQL执行效率插件
@Bean
@Profile({"dev","test"})//开启环境保护,保证我们的效率
public PerformanceInterceptor performanceInterceptor(){
    PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
    performanceInterceptor.setMaxTime(1);//设置执行sql的最大时间,如果超过则不执行
    performanceInterceptor.setFormat(true);//开启sql语句格式化
    return performanceInterceptor;
}

  • #设置开发环境 spring.profiles.active: dev

  • 测试使用

image-20220803151653927

条件构造器(QueryWrapper)

Wrapper 的作用就是用于定义各种各样的条件(where)。所以不管是查询、更新、删除都会用到Wrapper

封装关系

Wrapper  条件构造抽象类
    -- AbstractWrapper 查询条件封装,用于生成 sql 中的 where 语句。
        -- QueryWrapper Entity 对象封装操作类,用于查询。
        -- UpdateWrapper Update 条件封装操作类,用于更新。
        -- AbstractLambdaWrapper 使用 Lambda 表达式封装 wrapper
            -- LambdaQueryWrapper 使用 Lambda 语法封装条件,用于查询。
            -- LambdaUpdateWrapper 使用 Lambda 语法封装条件,用于更新。

常用条件

  • ( =, <>, >, >=, <, <= )
eq(R column, Object val); // 等价于 =,例: eq("name", "老王") ---> name = '老王'
ne(R column, Object val); // 等价于 <>,例: ne("name", "老王") ---> name <> '老王'
gt(R column, Object val); // 等价于 >,例: gt("name", "老王") ---> name > '老王'
ge(R column, Object val); // 等价于 >=,例: ge("name", "老王") ---> name >= '老王'
lt(R column, Object val); // 等价于 <,例: lt("name", "老王") ---> name < '老王'
le(R column, Object val); // 等价于 <=,例: le("name", "老王") ---> name <= '老王'
  • between、not between、in、not in
between(R column, Object val1, Object val2); 
// 等价于 between a and b, 例: between("age", 18, 30) ---> age between 18 and 30
notBetween(R column, Object val1, Object val2); 
// 等价于 not between a and b, 例: notBetween("age", 18, 30) ---> age not between 18 and 30
in(R column, Object... values); 
// 等价于 字段 IN (v0, v1, ...),例: in("age",{1,2,3}) ---> age in (1,2,3)
notIn(R column, Object... values); 
// 等价于 字段 NOT IN (v0, v1, ...), 例: notIn("age",{1,2,3}) ---> age not in (1,2,3)
inSql(R column, Object... values); 
// 等价于 字段 IN (sql 语句), 例: inSql("id", "select id from table where id < 3") ---> id in (select id from table where id < 3)
notInSql(R column, Object... values); 
// 等价于 字段 NOT IN (sql 语句)
  • 模糊匹配:(like)
like(R column, Object val); 
// 等价于 LIKE '%值%',例: like("name", "王") ---> name like '%王%'
notLike(R column, Object val);
// 等价于 NOT LIKE '%值%',例: notLike("name", "王") ---> name not like '%王%'
likeLeft(R column, Object val); // 等价于 LIKE '%值',例: likeLeft("name", "王") ---> name like '%王'
likeRight(R column, Object val); // 等价于 LIKE '值%',例: likeRight("name", "王") ---> name like '王%'
  • 分组、排序:(group、having、order)
groupBy(R... columns); // 等价于 GROUP BY 字段, ..., 例: groupBy("id", "name") ---> group by id,name
orderByAsc(R... columns); // 等价于 ORDER BY 字段, ... ASC, 例: orderByAsc("id", "name") ---> order by id ASC,name ASC
orderByDesc(R... columns); // 等价于 ORDER BY 字段, ... DESC, 例: orderByDesc("id", "name") ---> order by id DESC,name DESC
having(String sqlHaving, Object... params); // 等价于 HAVING ( sql语句 ), 例: having("sum(age) > {0}", 11) ---> having sum(age) > 11
  • 拼接、嵌套 sql:(or、and、nested、apply)
or(); // 等价于 a or b, 例:eq("id",1).or().eq("name","老王") ---> id = 1 or name = '老王'
or(Consumer<Param> consumer); // 等价于 or(a or/and b),or 嵌套。例: or(i -> i.eq("name", "李白").ne("status", "活着")) ---> or (name = '李白' and status <> '活着')
and(Consumer<Param> consumer); // 等价于 and(a or/and b),and 嵌套。例: and(i -> i.eq("name", "李白").ne("status", "活着")) ---> and (name = '李白' and status <> '活着')
nested(Consumer<Param> consumer); // 等价于 (a or/and b),普通嵌套。例: nested(i -> i.eq("name", "李白").ne("status", "活着")) ---> (name = '李白' and status <> '活着')
apply(String applySql, Object... params); // 拼接sql(若不使用 params 参数,可能存在 sql 注入),例: apply("date_format(dateColumn,'%Y-%m-%d') = {0}", "2008-08-08") ---> date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")
last(String lastSql); // 无视优化规则直接拼接到 sql 的最后,可能存若在 sql 注入。
exists(String existsSql); // 拼接 exists 语句。例: exists("select id from table where age = 1") ---> exists (select id from table where age = 1)
  • QueryWrapper 条件:
select(String... sqlSelect); // 用于定义需要返回的字段。例: select("id", "name", "age") ---> select id, name, age
select(Predicate<TableFieldInfo> predicate); // Lambda 表达式,过滤需要的字段。
lambda(); // 返回一个 LambdaQueryWrapper
  • UpdateWrapper 条件:
set(String column, Object val); // 用于设置 set 字段值。例: set("name", null) ---> set name = null
setSql(String sql); // 用于设置 set 字段值。例: setSql("name = '老李头'") ---> set name = '老李头'
lambda(); // 返回一个 LambdaUpdateWrapper

代码生成器

  • 添加依赖
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.4.1</version>
</dependency>
  • 创建测试类Autocode,执行代码
package com.my;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
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.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import java.util.ArrayList;

public class AutoCode {
    public static void main(String[] args) {
//构建代码生成器对象
        AutoGenerator autoGenerator = new AutoGenerator();
        /*配置策略*/
        //全局配置
        GlobalConfig config = new GlobalConfig();
        //代码生成的目录
        String path = System.getProperty("user.dir");
        //设置代码最终输出的目录
        config.setOutputDir(path + "");
        //设置作者
        config.setAuthor("");
        //配置是否打开目录,false 为不打开
        config.setOpen(false);
        //是否覆盖已有的
        config.setFileOverride(false);
        //去除service前缀
        config.setServiceName("%sService");
        //主键
        config.setIdType(IdType.ID_WORKER);//默认的
        //设置时间类型
        config.setDateType(DateType.ONLY_DATE);//只显示日期
        //是否生成Swagger文档
        config.setSwagger2(false);
        //设置策略
        autoGenerator.setGlobalConfig(config);
        /*设置数据源*/
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver"); //驱动
        dataSourceConfig.setUrl("jdbc:mysql://127.0.0.1:3306/demo?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");  //连接地址
        dataSourceConfig.setUsername("root"); //数据库用户名
        dataSourceConfig.setPassword("123456"); //数据库密码
        dataSourceConfig.setDbType(DbType.MYSQL);   //数据库类型
        //设置数据源
        autoGenerator.setDataSource(dataSourceConfig);
        /*项目包的配置*/
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setModuleName("my");//模块名
        packageConfig.setParent("com.my");//设置父目录
        packageConfig.setEntity("entity");//实体类包名
        packageConfig.setMapper("mapper");//mapper映射文件包名
        packageConfig.setService("service");//业务接口包名
        packageConfig.setServiceImpl("serviceIml");//业务层实现类包名
        packageConfig.setController("controller");//控制层包名
        //添加项目包配置
        autoGenerator.setPackageInfo(packageConfig);
        /*策略配置*/
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setInclude("userinfo");//表名
        strategyConfig.setNaming(NamingStrategy.underline_to_camel);//配置数据表与实体类名之间映射的策略
        strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);//配置数据表的字段与实体类的属性名之间映射的策略
        strategyConfig.setEntityLombokModel(true);//是否启用Lombok
        strategyConfig.setLogicDeleteFieldName("deleted");//逻辑删除字段名
        TableFill field1 = new TableFill("create_time", FieldFill.INSERT);//自动填充的字段 -数据插入时间
        TableFill field2 = new TableFill("update_time", FieldFill.INSERT_UPDATE);//自动填充的字段 -数据修改时间
        //自动填充配置集合
        ArrayList<TableFill> list = new ArrayList<>();
        list.add(field1);
        list.add(field2);
        strategyConfig.setTableFillList(list);
        strategyConfig.setVersionFieldName("version");//乐观锁
        strategyConfig.setRestControllerStyle(true);//配置 rest风格的控制器
        strategyConfig.setControllerMappingHyphenStyle(true);//配置驼峰转连字符
        //添加策略配置
        autoGenerator.setStrategy(strategyConfig);
        //执行
        autoGenerator.execute();
    }
}
文章作者: 郭远
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 郭远的博客空间
Mybatis Mybatis
喜欢就支持一下吧
打赏
微信 微信
支付宝 支付宝