Mybatis-Plus使用解析

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 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. 创建pojo,注意类名跟数据库表名要一样,不然就要加注解进行映射;
  2. 创建mapper包里面的类继承BaseMapper,所有的CRUD操作都已经编写完成了;
  3. 需要在著启动类上去扫描我们的mapper包下的所有接口:@MapperScan("com.bin.mapper");

 

配置日志

在application.properties

mybatis-plus.configuration.log-imp=org.apache.ibatis.logging.stdout.StdOutImpl

主键生成策略

  1. 对应数据库中的主键(uuid、自增id、雪花算法、redis、zookeeper)

分布式系统唯一id生成:https://www.cnblogs.com/haoxinyue/p/5208136.html

雪花算法:

snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。

     2.操作:在pojo类中的id加上注解:@TableId(type=IdType.ID_WORKER)

public enum IdType{
    AUTO(0), //数据库id自增
    NONE(1), //未设置主键
    INPUT(2), //手动输入
    ID_WORKER(3), //默认的全局唯一id
    UUID(4), //全局唯一id uuid
    ID_WORKER_STR(5); //ID_WORKER 字符串表示法
}

自动填充

创建时间、修改时间!这些操作一遍都是自动化完成,我们不希望手动更新!

阿里巴巴开发手册:所有的数据库表:gmt_create、gmt_modified几乎所有的表都要配置上!而且需要自动化!

方式一:数据库级别:在数据库中插入函数;

方式二:代码级别:在字段中增加注解

//字段添加填充内容
@TableFieId(fill=FieIdFill.INSERT)		//创建时间
private Date createTime;
@TableFieId(fill=FieIdFill.INSERT_UPDATE)	//更新时间
private Date updateTime;

编写处理器来处理这个注解即可!

@Slf4j   //增加打印日志
@Component  //一定不要忘记把处理器假到IOC容器中
public class MyMetaObjectHandler implements MetaObjectHandler {
    //插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
        this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug请升级到之后的版本如`3.3.1.8-SNAPSHOT`)
        /* 上面选其一使用,下面的已过时(注意 strictInsertFill 有多个方法,详细查看源码) 3.0以下使用 */
        //this.setFieldValByName("createTime", new Date(), metaObject);
        //this.setInsertFieldValByName("updateTime", new Date(), metaObject);
    }
    //更新时的填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
        this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug请升级到之后的版本如`3.3.1.8-SNAPSHOT`)
        /* 上面选其一使用,下面的已过时(注意 strictUpdateFill 有多个方法,详细查看源码) 3.0以下使用 */
        //this.setUpdateFieldValByName("updateTime", new Date(), metaObject);
    }
}

乐观锁

在面试过程中,我们经常会被问到乐观锁,悲观锁!这个其实非常简单!

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

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

乐观锁实现方式:

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

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

 

测试以下MP的乐观锁插件

  1. 给数据库中增加version字段
  2. 我们实体类加对应的字段

 

@version //乐观锁version注解
private Integer version;

    3.注册组件

//扫描我们mapper文件夹,有配置类的才加在这里,没有一般加载主启动类
@MapperScan("com.bin.mapper")
@EnableTransactionManagement //开启事务
@configuration //配置类
public class MyBatisPlusConfig{
    //注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
} 

    4.测试乐观锁失败!多线程下

 

//线程1
User user=UserMapper.selectById(1L);
user.setName("langshen111");
user.setEmail("[email protected]");
//模拟另一个线程执行了插队操作
User user2=UserMapper.selectById(1L);
user2.setName("langshen222");
user2.setEmail("[email protected]");
userMapper。updateById(user2);
//自旋锁来多次尝试提交!
userMapper。updateById(user); //如果没有乐观锁就会覆盖插队线程的值!

查询操作

userMapper.selectBatchIds(Arrays.asList(1,2,3)); //以多个id进行查询多条数据
//条件查询之一使用map操作
HashMap map=new HashMap<>();
map.put("name","浪神说java");
map.put("age",3);
userMapper.selectByMap(map);

分页查询

分页在网站使用的十分之多

1、原始的limit进行分页

2、pageHelper第三方插件

3、MP其实也内置了分页插件

使用步骤:

  1. 配置拦截器组件即可
 @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;
    }

    2.直接使用Page对象即可

//参数一:当前页;参数二:页面大小;
Page page=new Page<>(2,5);
userMapper.selectPage(page,null);
page.getRecords().forEach(System.out::println);
System.out.println(page.getTotal()); // 获取总数

逻辑删除

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

逻辑删除:在数据库中没有被移除,而是通过一个变量来让它失效!deleted=0 => deleted=1

步骤:

  1. 在数据库中增加一个deleted字段
  2. 实体类中增加属性
@TableLogic //逻辑删除
private Integer deleted;

     3.配置

//逻辑删除组件
@Bean
pulic ISqlInjector sqlInjector(){
    return new LogicSqlInjector();
}

在application.properties配置逻辑删除

mybatis-plus.global-config.db-config.logic-delete-value=1 
mybatis-plus.global-config.db-config.logic-not-delete-value=0

性能分析插件

//SQL执行效率插件,注意要在application.properties配置开发环境spring.profiles.active=dev
@Bean
@Profile({"dev","test"})//设置 dev test 环境开启,保证我们的效率
public PerformanceInterceptor performanceInterceptor(){
    PerformanceInterceptor performanceInterceptor=new PerformanceInterceptor();
    performanceInterceptor.setMaxTime(100);//设置sql执行的最大时间,如果超过了则不执行,单位毫秒
    performanceInterceptor.setFormat(true);//开启格式化代码
    return performanceInterceptor;
}

 

条件构造器

条件参数说明

查询方式

说明

setSqlSelect

设置 SELECT 查询字段

where

WHERE 语句,拼接 + WHERE 条件

and

AND 语句,拼接 + AND 字段=值

andNew

AND 语句,拼接 + AND (字段=值)

or

OR 语句,拼接 + OR 字段=值

orNew

OR 语句,拼接 + OR (字段=值)

eq

等于=

allEq

基于 map 内容等于=

ne

不等于<>

gt

大于>

ge

大于等于>=

lt

小于<

le

小于等于<=

like

模糊查询 LIKE

notLike

模糊查询 NOT LIKE

in

IN 查询

notIn

NOT IN 查询

isNull

NULL 值查询

isNotNull

IS NOT NULL

groupBy

分组 GROUP BY

having

HAVING 关键词

orderBy

排序 ORDER BY

orderAsc

ASC 排序 ORDER BY

orderDesc

DESC 排序 ORDER BY

exists

EXISTS 条件语句

notExists

NOT EXISTS 条件语句

between

BETWEEN 条件语句

notBetween

NOT BETWEEN 条件语句

addFilter

自由拼接 SQL

last

拼接在最后,例如:last("LIMIT 1")

 

//查询name不为空的用户,并且邮箱不为空的用户,年龄大于等于12
QueryWrapper wrapper=new QueryWrapper<>();
wrapper.isNotNull("name")
        .isNotNull("email")
        .ge("age",12)
userMapper.selectList(wrapper).forEach(System.out::println); 

//查询名字浪神说      
QueryWrapper wrapper=new QueryWrapper<>();
wrapper.eq("name","浪神说");
userMapper.selectOne(wrapper); //查询一个数据,出现多个结果使用List或者Map

//查询年龄在20~30岁之间的用户
QueryWrapper wrapper=new QueryWrapper<>();
wrapper.between("age",20,30); //区间
userMapper.selectCount(wrapper); //查询结果数

模糊查询:查询名字不带有e的,并且邮箱左边带t开头的
QueryWrapper wrapper=new QueryWrapper<>();
// 左和右  t%
wrapper.notLike("name","e").likeRight("email","t");
List> maps=userMapper.selectMaps(wrapper);  

QueryWrapper wrapper=new QueryWrapper<>();
// id在子查询中查出来
wrapper.inSql("id","select id from user where id<3");
List objects=userMapper.selectObjs(wrapper);  

QueryWrapper wrapper=new QueryWrapper<>();
// 通过id进行排序:降序
wrapper.ordeByDesc("id");
List objects=userMapper.selectList(wrapper);        

 

代码自动生成器

dao、pojo、service、controller都给我自己去编写完成!

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

//需要构建一个代码自动生成器 对象
AutoGenerator mpg = new AutoGenerator();
//配置策略
//1、全局配置
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.ID_WORKER);
gc.setDateType(DateType.ONLY_DATE);
gc.setSwagger2(true);
mpg.setGlobalConfig(gc);
//2、配置数据源
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/test?useSSL=true&useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&am");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
//3、包的配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("blog");
pc.setParent("com.kuang");
pc.setEntity("entity");
pc.setMapper("mapper");
pc.setService("service");
pc.setController("controller");
mpg.setPackageInfo(pc);
//4、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("user"); //设置要映射的表名,支持批量
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true); //自动lombok
strategy.setLogicDeleteFieldName("deleted");
//自动填充配置
TableFill gmtCreate = new TableFill("gmt_create",FieldFill.INSERT);
TableFill gmtModified = new TableFill("gmt_modified",FieldFill.INSERT_UPDATE);
ArrayList tableFills = new ArrayList<>();
tableFills.add(gmtCreate);
tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);
//乐观锁
strategy.setVersionFieldName("version");
strategy.setRestControllerStyle(true);
strategy.setCControllerMappingHyphenStyle(true); //localhost:8080/hello_id
mpg.setStrategy(strategy);
mpg.excute(); //执行

 

 

你可能感兴趣的:(插件,java,mybatis)