MybatisPlus3.4.1学习笔记

  • MybatisPlus3.4.1,注意版本差异
  • 个人基于"狂神说"教学视频的学习笔记,可能存在一定纰漏和错误
  • 部分内容来在MP官网和其他网络资源

特性

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

框架架构

=====================================
-----------
Scan Entity
-----------
	|
Reflection extraction
	|
	v
--------------------------					 ==============MybatisPlus==============
Analysis Table Name Column						--------------------------------
--------------------------							mybatis-plus-boot-starter
	|											--------------------------------
SQL:Insert、Update、Delete、Select 	《----	 ------------		 ------------
	|											 annotation			 extension
	v											------------ 		------------
---------------------------						------------        ------------
Injection Mybatis Container						    core			  generator
---------------------------						------------		------------
=====================================		  ======================================

依赖

​ 会自动维护Mybatis,不用再添加Mybatis的依赖

<!--单独使用-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus</artifactId>
    <version>xxx</version>
</dependency>

<!--集成SpringBoot-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>xxx</version>
</dependency>

案例application.yml基础配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mp
    username: root
    password: 123456

mybatis:
mybatis-plus:
  configuration:
    #驼峰:默认为true
    map-underscore-to-camel-case: true
    #日志,:默认实现,打印到控制台
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

案例表

CREATE TABLE `mp`  (
  `id` int(0) NOT NULL AUTO_INCREMENT,
  `last_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `gender` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `age` int(0) NULL DEFAULT NULL,
  `create_time` datetime(0) NULL DEFAULT NULL,
  `update_time` datetime(0) NULL DEFAULT NULL,
  `version` int(0) NULL DEFAULT 1 COMMENT '乐观锁字段',
  `deleted` int(0) NULL DEFAULT 0 COMMENT '逻辑删除',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

案例实体类

/**
 * MybatisPlus会默认使用实体类的类名到数据库中找对应的表
 * @TableName:
 *  value:表名(默认为空)
 *  resultMap:xml字段映射 resultMap的ID
 */
@TableName("mp")
@Data
public class Mp {
    /**
     * @TableId:
     *  value:指定表的主键名,若实体类属性和主键字段名相同,可省略
     *  type:指定主键策略
     */
    @TableId(type = IdType.AUTO)
    private Integer id;
    private String lastName;
    private String email;
    private Integer gender;
    private Integer age;
    //字段填充
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    //乐观锁字段
    @Version
    private Integer version;
    /**
     * 逻辑删除注解
     * @TableLogic
     * value:未删除值
     * delval:已删除值
     * 也可在application.yml全局配置
     * mybatis-plus.global-config.db-config.logic-delete-value=
     * mybatis-plus.global-config.db-config.logic-not-delete-value=
     */
    @TableLogic(value = "0",delval = "1")
    private Integer deleted;
}

1.注解说明

注解类包:mybatis-plus-annotation

@TableName

  • 描述:表名注解。MP默认使用实体类的类名到数据库中找对应的表。
属性类型必须指定默认值描述
valueString“”表名
schemaString“”schema
keepGlobalPrefixbooleanfalse是否保持使用全局的 tablePrefix 的值(如果设置了全局 tablePrefix 且自行设置了 value 的值)
resultMapString“”xml 中 resultMap 的 id
autoResultMapbooleanfalse是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建并注入)
excludePropertyString[]{}需要排除的属性名(@since 3.3.1)

关于autoResultMap的说明:

mp会自动构建一个ResultMap并注入到mybatis里(一般用不上).下面讲两句: 因为mp底层是mybatis,所以一些mybatis的常识你要知道,mp只是帮你注入了常用crud到mybatis里 注入之前可以说是动态的(根据你entity的字段以及注解变化而变化),但是注入之后是静态的(等于你写在xml的东西) 而对于直接指定typeHandler,mybatis只支持你写在2个地方:

  1. 定义在resultMap里,只作用于select查询的返回结果封装
  2. 定义在insertupdatesql的#{property}里的property后面(例:#{property,typehandler=xxx.xxx.xxx}),只作用于设置值 而除了这两种直接指定typeHandler,mybatis有一个全局的扫描你自己的typeHandler包的配置,这是根据你的property的类型去找typeHandler并使用.

@TableId

  • 描述:主键注解

    属性类型必须指定默认值描述
    valueString“”主键字段名,若实体类属性和主键字段名相同,可省略
    typeEnumIdType.NONE主键类型
    • type

      描述
      IdType.AUTO数据库ID自增
      IdType.NONE无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT,雪花算法)
      IdType.INPUTinsert前自行set主键值
      IdType.ASSIGN_ID分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
      IdType.ASSIGN_UUID分配UUID,主键类型为String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认default方法)

@TableField

  • 描述:字段注解(非主键)

    属性类型必须指定默认值描述
    valueString“”数据库字段名
    elString“”映射为原生 #{ ... } 逻辑,相当于写在 xml 里的 #{ ... } 部分
    existbooleantrue是否为数据库表字段
    conditionString“”字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s},参考(opens new window)
    updateString“”字段 update set 部分注入, 例如:update="%s+1":表示更新时会set version=version+1(该属性优先级高于 el 属性)
    insertStrategyEnumNDEFAULT举例:NOT_NULL: insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)
    updateStrategyEnumNDEFAULT举例:IGNORED: update table_a set column=#{columnProperty}
    whereStrategyEnumNDEFAULT举例:NOT_EMPTY: where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
    fillEnumFieldFill.DEFAULT字段自动填充策略
    selectbooleantrue是否进行 select 查询
    keepGlobalFormatbooleanfalse是否保持使用全局的 format 进行处理
    jdbcTypeJdbcTypeJdbcType.UNDEFINEDJDBC类型 (该默认值不代表会按照该值生效)
    typeHandlerClass<? extends TypeHandler>UnknownTypeHandler.class类型处理器 (该默认值不代表会按照该值生效)
    numericScaleString“”

关于jdbcTypetypeHandler以及numericScale的说明:

numericScale只生效于 update 的sql. jdbcTypetypeHandler如果不配合@TableName#autoResultMap = true一起使用,也只生效于 update 的sql. 对于typeHandler如果你的字段类型和set进去的类型为equals关系,则只需要让你的typeHandler让Mybatis加载到即可,不需要使用注解

@Version

  • 描述:乐观锁版本号注解

@TableLogic

  • 描述:逻辑删除注解
  • 属性:
    • value:未删除值
    • delval:已删除值

2.通用CRUD

​ mapper(dao)接口继承com.baomidou.mybatisplus.core.mapper.BaseMapper接口(BaseMapper<T>,T为封装该接口映射表数据的实体类),其封装了基本通用的CRUD方法。

@Mapper
@Repository
public interface MpMapper extends BaseMapper<Mp> {
}

2.1 Insert

  • BaseMapper.insert(obj)

    • 参数:实体类||Wrappe
    • 返回值:int,影响的数据库行数
    • 注意:自动回写插入数据的id(主键)
    @Test
    public void testCommonInert(){
        Mp mp=new Mp();
        mp.setLastName("neo");
        mp.setEmail("neo@rwby.com");
        mp.setGender(0);
        mp.setAge(20);
        System.out.println(mapper.insert(mp));
        System.out.println(mp.getId());
    }
    
    ==========sql日志和控制台输出==========
        
    ==>  Preparing: INSERT INTO mp ( last_name, email, gender, age ) VALUES ( ?, ?, ?, ? )
    ==> Parameters: neo(String), neo@rwby.com(String), 0(Integer), 20(Integer)
    <==    Updates: 1
        
    1
    9
    

2.2 Update

  • BaseMapper.updateById(obj)

    • 参数:实体类
    • 返回值:int,影响的数据库行数
    • 注意:作为参数的实体类对象若有属性值为空,则该属性会被忽略
    @Test
    public void testCommonUpdate(){
        Mp mp=new Mp();
        mp.setId(4);
        mp.setAge(22);
        mapper.updateById(mp);
    }
    
    ==========sql日志和控制台输出==========
        
    ==>  Preparing: UPDATE mp SET age=? WHERE id=?
    ==> Parameters: 22(Integer), 4(Integer)
    <==    Updates: 1
    
  • BaseMapper.update(obj,wrapper)

    • 参数:实体类&&Wrappe
    • 返回值:int,影响的数据库行数
    • 注意:作为参数的实体类对象若有属性值为空,则该属性会被忽略,其余属性被用于where子句"="判断。where子句的条件也可通过AbstractWrapper类的方法自定义
    @Test
    public void tesUpdate(){
        UpdateWrapper<Mp> wrapper=new UpdateWrapper<>();
        wrapper.eq("id",1).set("age",15);
        mapper.update(null,wrapper);
    }
    
    ==========sql日志和控制台输出==========
    
    ==>  Preparing: UPDATE mp SET age=? WHERE deleted=0 AND (id = ?)
    ==> Parameters: 15(Integer), 1(Integer)
    <==    Updates: 1
    

2.3 Select

  • BaseMapper.selectById(Serializable id)

    • 通过id查询
    • 参数:实现Serializable 接口的obj
    • 返回值:BaseMapper接口传入的泛型T
    @Test
    public void testCommonSelect(){
        System.out.println(mapper.selectById(4));
    }
    
    ==========sql日志和控制台输出==========
        
    ==>  Preparing: SELECT id,last_name,email,gender,age FROM mp WHERE id=?
    ==> Parameters: 4(Integer)
    <==    Columns: id, last_name, email, gender, age
    <==        Row: 4, neo, neo@rwby.com, 0, 22
    <==      Total: 1
        
    Mp{id=4, lastName='neo', email='neo@rwby.com', gender=0, age=22}
    
  • BaseMapper.SelectOne(Wrapper<T> queryWrapper)

    • 通过条件构造器查询一个
    • 参数:QueryWrapper
    • 返回值:T
    • 注意:当new QueryWrapper(T)时,根据T的非空属性进行查询,最多只能查询一个,查询结果为多个时报错
    @Test
    public void testSelectOne(){
        //通过多个字段查询
        Mp mp=new Mp();
        mp.setId(4);
        mp.setLastName("neo");
        Wrapper queryWrapper=new QueryWrapper(mp);
        System.out.println(mapper.selectOne(queryWrapper));
    }
    
    ==========sql日志和控制台输出==========
        
    ==>  Preparing: SELECT id,last_name,email,gender,age FROM mp WHERE id=? AND last_name=?
    ==> Parameters: 4(Integer), neo(String)
    <==    Columns: id, last_name, email, gender, age
    <==        Row: 4, neo, neo@rwby.com, 0, 22
    <==      Total: 1
        
    Mp{id=4, lastName='neo', email='neo@rwby.com', gender=0, age=22}
    
  • BaseMapper.selectList(Wrapper<T> queryWrapper)

    • 根据条件构造器查询多个
    • 参数:QueryWrapper
    • 返回值:List<T>
    • 注意:
      • QueryWrapper为null时,查询所有
      • new QueryWrapper(T)时,根据T的非空属性进行查询
    @Test
    public void  testMp(){
        mpMapper.selectList(null).forEach(System.out::println);
    }
    
    ==========sql日志和控制台输出==========
    
    ==>  Preparing: SELECT id,last_name,email,gender,age FROM mp
    ==> Parameters: 
    <==    Columns: id, last_name, email, gender, age
    <==        Row: 1, Tom, Tom@cam.com, 1, 22
    <==        Row: 2, Jerry, Jerry@cam.com, 1, 25
    <==        Row: 3, Ruby, Ruby@rwby.com, 0, 19
    <==        Row: 4, neo, neo@rwby.com, 0, 22
    <==      Total: 4
    
    Mp{id=1, lastName='Tom', email='Tom@cam.com', gender=1, age=22}
    Mp{id=2, lastName='Jerry', email='Jerry@cam.com', gender=1, age=25}
    Mp{id=3, lastName='Ruby', email='Ruby@rwby.com', gender=0, age=19}
    Mp{id=4, lastName='neo', email='neo@rwby.com', gender=0, age=22}
    
  • BaseMapper.selectBatchIds(Collection<? extends Serializable> idList)

    • 通过id集合查询
    • 参数:Collection<? extends Serializable>
    • 返回值:List<?>
    @Test
    public void testSelectBatchIds(){
        List<Integer> ids=new ArrayList(){{add(1);add(2);add(3);add(4);}};
        mapper.selectBatchIds(ids).forEach(System.out::println);
    }
    
    ==========sql日志和控制台输出==========
    
    ==>  Preparing: SELECT id,last_name,email,gender,age FROM mp WHERE id IN ( ? , ? , ? , ? )
    ==> Parameters: 1(Integer), 2(Integer), 3(Integer), 4(Integer)
    <==    Columns: id, last_name, email, gender, age
    <==        Row: 1, Tom, Tom@cam.com, 1, 22
    <==        Row: 2, Jerry, Jerry@cam.com, 1, 25
    <==        Row: 3, Ruby, Ruby@rwby.com, 0, 19
    <==        Row: 4, neo, neo@rwby.com, 0, 22
    <==      Total: 4
    
    Mp{id=1, lastName='Tom', email='Tom@cam.com', gender=1, age=22}
    Mp{id=2, lastName='Jerry', email='Jerry@cam.com', gender=1, age=25}
    Mp{id=3, lastName='Ruby', email='Ruby@rwby.com', gender=0, age=19}
    Mp{id=4, lastName='neo', email='neo@rwby.com', gender=0, age=22}
    
  • BaseMapper.selectByMap( Map<String, Object> columnMap)

    • 通过Map封装条件查询
    • 参数:Map<String, Object>
    • 返回值:List<T>,T为BaseMapper接口传入的泛型
    • 注意: Key,表字段名;Value,字段取值(条件)。columnMap为null时,查询所有
    @Test
    public void testSelectByMap(){
        Map<String,Object> columnMap=new HashMap();
        columnMap.put("last_name","Tom");
        columnMap.put("gender",1);
        mapper.selectByMap(columnMap).forEach(System.out::println);
    }
    
    ==========sql日志和控制台输出==========
    
    ==>  Preparing: SELECT id,last_name,email,gender,age FROM mp WHERE gender = ? AND last_name = ?
    ==> Parameters: 1(Integer), Tom(String)
    <==    Columns: id, last_name, email, gender, age
    <==        Row: 1, Tom, Tom@cam.com, 1, 22
    <==      Total: 1
    
    Mp{id=1, lastName='Tom', email='Tom@cam.com', gender=1, age=22}
    
  • BaseMapper.selectPage(E page, Wrapper<T> queryWrapper)

    • 分页查询
    • 参数:
      • com.baomidou.mybatisplus.extension.plugins.pagination.Page<T>
        • new Page(current,size)
          • current,当前页
          • size,每页显示条数,默认 10
      • QueryWrapper(T)
    • 返回值:Page
    • 注意:
    • 不是通过limit进行分页查询,而是使用Mybatis的RowBounds进行内存分页
      • QueryWrapper为空时,查询所有
    @Test
    public void testSelectPage(){
        mapper.selectPage(new Page<>(1,4),null)
                .getRecords().forEach(System.out::println);
    }
    
    ==========sql日志和控制台输出==========
    
    ==>  Preparing: SELECT id,last_name,email,gender,age FROM mp
    ==> Parameters: 
    <==    Columns: id, last_name, email, gender, age
    <==        Row: 1, Tom, Tom@cam.com, 1, 22
    <==        Row: 2, Jerry, Jerry@cam.com, 1, 25
    <==        Row: 3, Ruby, Ruby@rwby.com, 0, 19
    <==        Row: 4, neo, neo@rwby.com, 0, 22
    <==      Total: 4
    
    Mp{id=1, lastName='Tom', email='Tom@cam.com', gender=1, age=22}
    Mp{id=2, lastName='Jerry', email='Jerry@cam.com', gender=1, age=25}
    Mp{id=3, lastName='Ruby', email='Ruby@rwby.com', gender=0, age=19}
    Mp{id=4, lastName='neo', email='neo@rwby.com', gender=0, age=22}
    

3. 自动填充

​ “创建时间”、“修改时间”这个操作都是自动化完成的。

3.1 数据库级别

​ 相应字段设置默认值,勾选“自动更新”。

3.2 代码级别

  1. 在实体类相应属性添加注解**@TableField(fill=FieldFill)**。

    • enum FieldFill
      • DEFAULT,默认,不自动填充
      • INSERT,插入时自动填充
      • UPDATE,更新时自动填充
      • INSERT_UPDATE,插入和更新时自动填充
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    
  2. 编写注解处理器

    • 注解**@Component**
    • 实现com.baomidou.mybatisplus.core.handlers.MetaObjectHandler
    • 重写对应方法(以insert、update为例)
      • 使用MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)方法
        • String fieldName:属性(字段)名
        • Object fieldVal:字段值
        • MetaObject metaObject:处理的数据
    @Slf4j
    @Component
    public class FillHandler implements MetaObjectHandler {
    
        //插入的填充策略
        @Override
        public void insertFill(MetaObject metaObject) {
            log.info("插入填充");
            this.setFieldValByName("createTime",new Date(),metaObject);
            this.setFieldValByName("updateTime",new Date(),metaObject);
        }
    
        //更新的填充策略
        @Override
        public void updateFill(MetaObject metaObject) {
            log.info("更新填充");
            this.setFieldValByName("updateTime",new Date(),metaObject);
        }
    }
    

4. 乐观锁

  • 乐观锁:总是认为不会出现问题,无论干什么都不上锁。若出现问题,再更新值测试(自旋、CAS)。
  • 悲观锁:认为总是出现问题,无论干什么都会先上锁再去操作(synchronized)。

乐观锁实现方式:

  • 取出记录,获取当前version(oldVersion)
  • 更新时,带上并更新此version
  • 执行更新set version = newVersion where version = oldVersion
    version != oldVersion,更新失败

4.1 MP实现乐观锁

  • 数据库添加记录版本号的字段(数字)

  • 实体类对应属性添加**@Version**注解

    //乐观锁字段
    @Version
    private Integer version;
    
  • 编写配置类,注册乐观锁拦截器com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor

    @Configuration
    public class OptLockingConfig {
       
        //注册乐观锁插件
        @Bean
        public OptimisticLockerInnerInterceptor optLockerInnerInterceptor(){
            return new OptimisticLockerInnerInterceptor();
        }
    }
    

5. 逻辑删除

  • 物理删除:从数据库中直接移除
  • 逻辑删除:没有从数据库中移除,而是通过一个变量使其失效

5.1 MP实现逻辑删除

  • 数据库添加逻辑删除的字段

  • 实体类对应属性添加**@TableLogic**注解

    @TableLogic(value = "0",delval = "1")
    /**
     * value:未删除值
     * delval:已删除值
     */
    private Integer deleted;
    
  • 也可在application.yml中进行全局配置,此时不用再对@TableLogic的属性进行赋值

    mybatis-plus:
      global-config:
        db-config:
          #未删除
          logic-not-delete-value: 0
          #已删除
          logic-delete-value: 1
    
  • 测试

    本质是更新操作,查询时会自动过滤逻辑删除字段

    @Test
    public void LogicTest(){
        mapper.deleteById(1);
        mapper.selectById(1);
    }
    
    ==========sql日志和控制台输出==========
    
    ==>  Preparing: UPDATE mp SET deleted=1 WHERE id=? AND deleted=0
    ==> Parameters: 1(Integer)
    <==    Updates: 1
        
    ==>  Preparing: SELECT id,last_name,email,gender,age,create_time,update_time,version,deleted FROM mp WHERE id=? AND deleted=0
    ==> Parameters: 1(Integer)
    <==      Total: 0
    

6. 性能分析打印插件

​ 性能分析插件PerformanceInterceptor3.2.0版本被废除,3.2.0以上版本可以使用性能分析打印插件。该插件有性能损耗,建议在测试环境使用。

  • 依赖

    <dependency>
        <groupId>p6spy</groupId>
        <artifactId>p6spy</artifactId>
        <version>3.9.1</version>
    </dependency>
    
  • 增加配置spy.properties

    • 打印出sql为null,在excludecategories增加commit
    • 批量操作不打印sql,去除excludecategories中的batch
    #3.2.1以上使用
    modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
    #3.2.1以下使用或者不配置
    #modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
    # 自定义日志打印
    logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
    #日志输出到控制台
    appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
    # 使用日志系统记录 sql
    #appender=com.p6spy.engine.spy.appender.Slf4JLogger
    # 设置 p6spy driver 代理
    deregisterdrivers=true
    # 取消JDBC URL前缀
    useprefix=true
    # 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
    excludecategories=info,debug,result,commit,resultset
    # 日期格式
    dateformat=yyyy-MM-dd HH:mm:ss
    # 实际驱动可多个
    #driverlist=org.h2.Driver
    # 是否开启慢SQL记录
    outagedetection=true
    # 慢SQL记录标准 2 秒
    outagedetectioninterval=2
    
  • 修改application.yml数据源配置

    • driver-class-name 为 p6spy 提供的驱动类
    • url 前缀为 jdbc:p6spy:对应数据库连接地址
    spring:
      datasource:
        driver-class-name: com.p6spy.engine.spy.P6SpyDriver
        url: jdbc:p6spy:mysql://localhost:3306/mp
        username: ***
        password: ***
    
  • 测试

    @Test
    public void PerformanceTest(){
        mapper.selectById(1);
    }
    
    ==========sql日志和控制台输出==========
    
    ==>  Preparing: SELECT id,last_name,email,gender,age,create_time,update_time,version,deleted FROM mp WHERE id=? AND deleted=0
    ==> Parameters: 1(Integer)
     Consume Time:15 ms 2021-01-07 21:55:57
     Execute SQL:SELECT id,last_name,email,gender,age,create_time,update_time,version,deleted FROM mp WHERE id=1 AND deleted=0
    
    <==    Columns: id, last_name, email, gender, age, create_time, update_time, version, deleted
    <==        Row: 1, TomCat, Tom@cam.com, 1, 22, 2021-01-05 20:34:25, 2021-01-05 21:18:00, 1, 0
    <==      Total: 1
    

7. 条件构造器Wrapper

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

这段内容太多了,建议参考官方文档

关于com.baomidou.mybatisplus.core.conditions.Wrapper中的方法,个人理解(仅仅是个人理解)是用于"指导"sql生成,其方法主要是判空(指导生成条件子句)和拼接sql。

一个简单的控制变量

  • Wrapper部分源码

    /**
     * 深层实体判断属性
     *
     * @return true 为空
     */
    public boolean isEmptyOfEntity() {
        return !nonEmptyOfEntity();
    }
    
    /**
     * 查询条件为空(不包含entity)
     */
    public boolean isEmptyOfNormal() {
        return CollectionUtils.isEmpty(getExpression().getNormal());
    }
    
    /**
     * 查询条件为空(包含entity)
     */
    public boolean isEmptyOfWhere() {
        return isEmptyOfNormal() && isEmptyOfEntity();
    }
    
  • 测试上诉方法

    @Test
    public void wrapper(){
        Mp mp1=new Mp();
        Mp mp2=new Mp();
        mp2.setAge(15);
    
        //传入属性全为空的entity,无条件
        QueryWrapper<Mp> wrapper1=new QueryWrapper<>(mp1);
        //传入属性不全为空的entity,无条件
        QueryWrapper<Mp> wrapper2=new QueryWrapper<>(mp2);
        //无entity,有条件
        QueryWrapper<Mp> wrapper3=new QueryWrapper<>();
        wrapper3.orderByAsc("age");
        //无entity,无条件
        QueryWrapper<Mp> wrapper4=new QueryWrapper<>();
        
        ...
        
    }
    
  • 输出结果

    wrapper1,属性全为空的entity,无条件:

    entity判空:true

    where判空(不包含entity):true

    where判空(包含entity):true


    wrapper2,属性不全为空的entity,无条件:

    entity判空:false

    where判空(不包含entity):true

    where判空(包含entity):false


    wrapper3,无entity,有条件:

    entity判空:true

    where判空(不包含entity):true

    where判空(包含entity):true


    wrapper4,无entity,无条件:

    entity判空:true

    where判空(不包含entity):true

    where判空(包含entity):true


8. 代码生成器

依赖

​ MyBatis-Plus 从 3.0.3 之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖。

<!--代码生成器-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.4.1</version>
</dependency>
<!--默认支持的模版-->
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.2</version>
</dependency>

demo

​ 生成器相关的包com.baomidou.mybatisplus.generator

/**
 * 代码生成器
 */
public class MpAg {

    public static void main(String[] args) {
        //代码生成器对象
        AutoGenerator ag=new AutoGenerator();

        //1.全局配置
        GlobalConfig gc=new GlobalConfig();  //生成器全局配置对象
        String path=System.getProperty("user.dir"); //当前项目路径
        gc.setOutputDir(path+"/mp_08_auto_generator/src/main/java/com") //设置输出路径
            .setAuthor("asd") //设置作者
            .setOpen(false) //生成后是否打开资源管理器(windows文件夹)
            .setFileOverride(false) //是否覆盖
            .setServiceName("%sService") //设置service层接口名称(去"I"前缀)
            .setIdType(IdType.AUTO) //设置主键策略(自增)
            .setDateType(DateType.ONLY_DATE) //设置日期类型
            .setSwagger2(true); //自动配置Swagger

        //2.配置数据源
        DataSourceConfig dsc = new DataSourceConfig(); //数据源配置对象
        dsc.setDriverName("com.mysql.cj.jdbc.Driver")
             .setUrl("jdbc:mysql://localhost:3306/mp")
             .setUsername("root")
             .setPassword("123456")
             .setDbType(DbType.MYSQL);

        //3.包配置
        PackageConfig pc=new PackageConfig(); //包配置对象
        pc.setParent("study.ag") //总路径
             .setModuleName("mp") //上级包名
             .setEntity("entity") //实体类包名
             .setMapper("mapper") //dao层包名
             .setService("service") //service层包名
             .setServiceImpl("service.impl") //service实现类包名
             .setController("controller"); //controller层包名

        //4.策略配置
        List<TableFill> tableFills=new ArrayList();
        tableFills.add(new TableFill("creat", FieldFill.INSERT));
        tableFills.add(new TableFill("update", FieldFill.INSERT_UPDATE));

        StrategyConfig sc=new StrategyConfig(); //策略配置对象
        sc.setInclude("mp") //映射的表
             .setNaming(NamingStrategy.underline_to_camel) //表名映射策略(下划线->驼峰)
             .setColumnNaming(NamingStrategy.underline_to_camel) //列名映射策略(下划线->驼峰)
             //.setSuperXXXClass() 自己的XXX父类,没有则不设置
             .setEntityLombokModel(true) //实体类是否开启Lombok
             .setRestControllerStyle(true) //Controller是否采用RestFul风格
             .setControllerMappingHyphenStyle(true) //url下划线连接
             .setLogicDeleteFieldName("deleted") //逻辑删除属性名
             .setTableFillList(tableFills) //自动填充(List<TableFill>)
             .setVersionFieldName("version"); //乐观锁版本属性名

        //将配置放入AutoGenerator
        ag.setGlobalConfig(gc)
                .setDataSource(dsc)
                .setPackageInfo(pc)
                .setStrategy(sc);

        //执行
        ag.execute();
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值