【框架专题】——MybatisPlus应用——技术应用手册

baseMapper

baseMapper——实体类标注

实体类演示

@TableName("process_agent_manage")
public class AgentManageConfigEntity extends SuperEsmEntity{
        @TableField("authorizer_id")
        private String authorizerId;
        @TableField("agent_id")
        private String agentId;
        @TableField("expiration_begin")
        private Long expirationBegin;
        @TableField("expiration_end")
        private Long expirationEnd;
        @TableField("agent_type")
        private Integer agentType;
        @TableField("step_code")
        private String stepCode;
        @TableField("remark")
        private String remark;
        @TableField("corp_id")
        private String corpId;
        @TableLogic
        @TableField("is_del")
        private Integer isDel;
        @TableField("ref_agent_id")
        private Long refAgentId;
}

实体类注解大全

    @TableField(exist = false) 不是数据库字段
    @TableLogic 标记为逻辑删除
    @TableField 标记她的数据名
    @TableId 标记为主键

baseMapper——mapper构造

@Repository
public interface TestMysqlMapper extends BaseMapper<TemEntity> {
}

LambdaQueryWrapper<TemEntity> queryWrapper = 
	 Wrappers.<TemEntity>lambdaQuery()
 		.eq(TemEntity::getNeedAmount, 0);
LambdaUpdateWrapper<TemEntity> updateWrapper = 
	 Wrappers.<TemEntity>lambdaUpdate(new TemEntity()
	 	.setAccount_id("1111"))
	 	.eq(TemEntity::getNeedAmount, 0);
LambdaQueryWrapper<TemEntity> queryWrapper2 = 
	new QueryWrapper<TemEntity().lambda()
	.eq(TemEntity::getNoAmount, 0);
LambdaUpdateWrapper<TemEntity> updateWrapper2 = 
	new UpdateWrapper<TemEntity>(
		newTemEntity().setAccount_id("1111")).lambda()
		.eq(TemEntity::getNoAmount, 0);

baseMapper——方法调用大全(插入)

插入一个

approveConfigMapper.insert(approveConfigEntity);

baseMapper——方法调用大全(更新)

按照id更新一个

id放在了entity里面

approveConfigMapper.updateById(entity);

按照条件更新一个

条件通过QueryWrapper显示

approveConfigMapper.update(entity, new QueryWrapper<ApproveConfigEntity>().lambda()
                .eq(ApproveConfigEntity::getId, approveConfigInputVO.getId())
                .eq(ApproveConfigEntity::getCorpId, approveConfigInputVO.getCorpId()))

baseMapper——方法调用大全(删除)

按照id删除一个

 billFinanceConfigMapper.deleteBatchIds(ids);

按照id删除多个

 billFinanceConfigMapper.deleteById(id);

按照条件删除

billFinanceConfigMapper.delete(new QueryWrapper<BillFinanceConfigEntity>().lambda()
                .eq(BillFinanceConfigEntity::getCorpId, billFinanceConfigInputVO.getCorpId())
                .eq(BillFinanceConfigEntity::getDeptId, billFinanceConfigInputVO.getDeptId())
);

baseMapper——方法调用大全(查询)

按照id查询单个

这个方法查出来的,如果存在多个就会报错,可以拿唯一索引或者主键作为条件

ApproveConfigEntity approveConfigEntity = approveConfigMapper.selectOne(new QueryWrapper<ApproveConfigEntity>().lambda()
                .eq(ApproveConfigEntity::getCorpId, billFinanceConfigInputVO.getCorpId())
                .eq(ApproveConfigEntity::getDeptId, billFinanceConfigInputVO.getDeptId()));

按照条件查询多个(不分页)

List<BillFinanceConfigEntity> billFianceList = billFinanceConfigMapper.selectList(new QueryWrapper<BillFinanceConfigEntity>().lambda()
                .eq(BillFinanceConfigEntity::getCorpId, approveConfigInputVO.getCorpId())
                .eq(BillFinanceConfigEntity::getDeptId, approveConfigInputVO.getDeptId())
);

按照条件查询多个(分页)

appRefsCurrencyMapper.selectPage(new Page<>(po.getPageIndex(), po.getPageSize()), new QueryWrapper<AppRefsCurrencyEntity>()
                .lambda()
                .like(StringUtils.isNotEmpty(po.getKeyword()), AppRefsCurrencyEntity::getCuryName, po.getKeyword()))

分页查询mapper应用

    IPage<AgentManageConfigVO> queryList(Page<AgentManageConfigEntity> objecPage, @Param("po") AgentManageConfigInputVO po);

baseMapper——高级条件构造

allEq

filter : 过滤函数,是否允许字段传入比对条件中
null2IsNull:是否过滤null

allEq(Map<R, V> params)
allEq(Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)1: allEq({id:1,name:"老王",age:null})--->id = 1 and name = '老王' and age is null
例2: allEq({id:1,name:"老王",age:null}, false)--->id = 1 and name = '老王'

ne

不等于

ne(R column, Object val)

func

通过java内的条件决定用哪个语句,多重分支时适用

func(i -> if(true) {
		i.eq("id", 1)
	} else{
		i.ne("id", 1)
	}
)

inSql

inSql(“age”, “1,2,3,4,5,6”)—>age in (1,2,3,4,5,6)
inSql(“id”, “select id from table where id < 3”)—>id in (select id from table where id < 3)

inSql(R column, String inValue)

nested

用and组合里面的条件

nested(
	i -> i.eq("name", "李白").ne("status", "活着"))
	(name = '李白' and status <> '活着')

apply

拼接sql,通过{index}可以取到参数,有sql注入风险

last(String lastSql): apply("id = 1")--->id = 1: apply("date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")--->date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'"): apply("date_format(dateColumn,'%Y-%m-%d') = {0}", "2008-08-08")--->date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")

last

无视优化规则,尾部直接拼接sql

last(String lastSql)

exists

exists(String existsSql)
exists("select id from table where age = 1")--->exists (select id from table where age = 1)

MybatisPlus——策略配置

策略配置——逻辑删除

基本配置

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: is_delete  # 统一全局状态字段名(一般不全局,有些是物理删除)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

标记法

@TableLogic
private Integer is_delete;

影响

插入: 不作限制,手动指定条件字段
查找:自动忽略删除状态的数据
更新:自动忽略删除状态的数据
删除:转变为更新

调用

   testMysqlMapper.deleteById(1)

策略配置——通用枚举

指定好对枚举字段的解析,然后mapper可以使用枚举作为参数传给SQL

@EnumValue注解法

ublic enum GradeEnum {
    PRIMARY(1, "小学"),  SECONDORY(2, "中学"),  HIGH(3, "高中");
    GradeEnum(int code, String descp) {
        this.code = code;
        this.descp = descp;
    }
    @EnumValue//标记数据库存的值是code
    private final int code;
    //。。。
}

IEnum接口法

public enum AgeEnum implements IEnum<Integer> {
    ONE(1, "一岁"),
    TWO(2, "二岁"),
    THREE(3, "三岁");
    
    private int value;
    private String desc;
    
    @Override
    public Integer getValue() {
        return this.value;
    }
}

全局配置

mybatis-plus:
    # 支持统配符 * 或者 ; 分割
    typeEnumsPackage: com.jm.values.enums

序列化配置

前端对枚举的转化

  @Bean
    public Jackson2ObjectMapperBuilderCustomizer customizer(){
        return builder -> builder.featuresToEnable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
    }
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
public enum GradeEnum {

    PRIMARY(1, "小学"),  SECONDORY(2, "中学"),  HIGH(3, "高中");

    GradeEnum(int code, String descp) {
        this.code = code;
        this.descp = descp;
    }

    @EnumValue
  	@JsonValue	//标记响应json值
    private final int code;
}

策略配置——类型处理器

mybatis中已经蕴含了大量的对jdk原生类型的数据对应处理,但是我们的自定义类型则需要通过类型处理器去特殊处理

局部

@Data
@Accessors(chain = true)
@TableName(autoResultMap = true)
public class User {
    private Long id;
  /**
     * 注意!! 必须开启映射注解 @TableName(autoResultMap = true)
     * 这个需求就是前端对应一个实体数据传过来
     * 我们不需要手动调用json存该string
     * 而是调用类型处理器
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    private OtherInfo otherInfo;

}

全局(待更新)

策略配置——乐观锁

配置

@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
    return new OptimisticLockerInterceptor();
}

实体

@Version
private Integer version;

支持

int,Integer,long,Long,Date,Timestamp,LocalDateTime

原理

	取出记录时\前端自带,获取当前version
	执行更新时插件自动添加, set version = newVersion where version = oldVersion

策略配置——公共字段填充

公共字段注入

/*
 * 自动填充处理器,用于填充公共字段
 * 无值则入库会是null
 * strict则是实体类的注解说明以及实体类的类型来决定是否注入
 * fillStrategy:直接注入,不管策略如何spring-boot-maven-plugin
 * @author luozhifeng
 * @date 2020/9/29
 */
@Component
@Slf4j
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)
    }

    @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)
    }
}

公共字段配置

/**
 *
 * 默认不处理 DEFAULT
 * 插入填充字段 INSERT
 * 更新填充字段 UPDATE
 * 插入和更新填充字段 INSERT_UPDATE
 * 注解则是指定该属性在对应情况下必有值,如果无值则入库会是null
 */
public class SuperEntity {
    private static final long  serialVersionUID =4359709211352400087L;
    @TableId(type = IdType.ID_WORKER)
    private Long id;
    @TableField(value = "create_by", fill = FieldFill.INSERT)
    private String createBy;
    @TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
    private String updateBy;
    @TableField(value = "create_date", fill = FieldFill.INSERT)
    private long createDate;
    @TableField(value = "update_date", fill = FieldFill.INSERT_UPDATE)
    private long updateDate;
}

MybatisPlus——SQL注入器

所有注入器都是通过返回一个SqlParserList整合进mybatis

 @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        paginationInterceptor.setSqlParserList(getISqlParser());
        return paginationInterceptor;
    }

阻断拦截器

如果指定条件满足则直接return,最后向应用删除失败而不会进入真正的processDelete

   public List<ISqlParser> getISqlParser(){
        List<ISqlParser> sqlParserList = new ArrayList<>();
        sqlParserList.add(new BlockAttackSqlParser() {
            @Override
            public void processDelete(Delete delete) {
                if ("user".equals(delete.getTable().getName())) {
                    return ;
                }
                super.processDelete(delete);
            }
        });
        return sqlParserList;
    }

表名拦截器

 public List<ISqlParser> getISqlParser(){
        List<ISqlParser> sqlParserList = new ArrayList<>();
        DynamicTableNameParser dynamicTableNameParser = new DynamicTableNameParser();
        dynamicTableNameParser.setTableNameHandlerMap(new HashMap<String, ITableNameHandler>(2) {{
            put("user", (metaObject, sql, tableName) -> {
                 
                // metaObject、sql,我們可以以這些作爲依据来生成表名
                //下面这个是随机时间
                String year = "_2018";
                int random = new Random().nextInt(10);
                if (random % 2 == 1) {
                    year = "_2019";
                }
                return tableName + year;
            });
        }});
        sqlParserList.add(dynamicTableNameParser);
        return sqlParserList;
    }

租户拦截器(有点复杂)

MybatisPlus——重写场景

自定义——BaseMapper

装饰BaseMapper

public interface MyBaseMapper<T> extends BaseMapper<T> {
    Integer deleteAll();
    int myInsertAll(T entity);
    int mysqlInsertAllBatch(@Param("list") List<T> batchList);
}

创建实现链接器

method:指定接口中的方法名完成连接
sql :最终执行的sql

public class DeleteAll extends AbstractMethod {
    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        /* 执行 SQL ,动态 SQL 参考类 SqlMethod */
        String sql = "delete from " + tableInfo.getTableName();
        /* mapper 接口方法名一致 */
        String method = "deleteAll";
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
        return this.addDeleteMappedStatement(mapperClass, method, sqlSource);
    }
}

MyInsertAll

主要演示怎么通过实体类的TableInfo 完成插入

public class MyInsertAll extends AbstractMethod {

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        String sql = "insert into %s %s values %s";
        StringBuilder fieldSql = new StringBuilder();
        fieldSql.append(tableInfo.getKeyColumn()).append(",");
        StringBuilder valueSql = new StringBuilder();
        valueSql.append("#{").append(tableInfo.getKeyProperty()).append("},");
        tableInfo.getFieldList().forEach(x->{
            fieldSql.append(x.getColumn()).append(",");
            valueSql.append("#{").append(x.getProperty()).append("},");
        });
        fieldSql.delete(fieldSql.length()-1, fieldSql.length());
        fieldSql.insert(0, "(");
        fieldSql.append(")");
        valueSql.insert(0, "(");
        valueSql.delete(valueSql.length()-1, valueSql.length());
        valueSql.append(")");
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, String.format(sql, tableInfo.getTableName(), fieldSql.toString(), valueSql.toString()), modelClass);
        return this.addInsertMappedStatement(mapperClass, modelClass, "myInsertAll", sqlSource, new NoKeyGenerator(), null, null);
    }
}

MysqlInsertAllBatch

主要演示sql怎么样访问注解值
prepareValuesSqlForMysqlBatch中")

public class MysqlInsertAllBatch extends AbstractMethod {

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        final String sql = "";
        final String fieldSql = prepareFieldSql(tableInfo);
        final String valueSql = prepareValuesSqlForMysqlBatch(tableInfo);
        final String sqlResult = String.format(sql, tableInfo.getTableName(), fieldSql, valueSql);
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
        return this.addInsertMappedStatement(mapperClass, modelClass, "mysqlInsertAllBatch", sqlSource, new NoKeyGenerator(), null, null);
    }

    private String prepareFieldSql(TableInfo tableInfo) {
        StringBuilder fieldSql = new StringBuilder();
        fieldSql.append(tableInfo.getKeyColumn()).append(",");
        tableInfo.getFieldList().forEach(x -> {
            fieldSql.append(x.getColumn()).append(",");
        });
        fieldSql.delete(fieldSql.length() - 1, fieldSql.length());
        fieldSql.insert(0, "(");
        fieldSql.append(")");
        return fieldSql.toString();
    }

    private String prepareValuesSqlForMysqlBatch(TableInfo tableInfo) {
        final StringBuilder valueSql = new StringBuilder();
        valueSql.append("");
        valueSql.append("#{item.").append(tableInfo.getKeyProperty()).append("},");
        tableInfo.getFieldList().forEach(x -> valueSql.append("#{item.").append(x.getProperty()).append("},"));
        valueSql.delete(valueSql.length() - 1, valueSql.length());
        valueSql.append("");
        return valueSql.toString();
    }
}

创建全局注入器

public class MyLogicSqlInjector extends DefaultSqlInjector {

    /**
     * 如果只需增加方法,保留MP自带方法
     * 可以super.getMethodList() 再add
     * @return
     */
    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass);
        methodList.add(new DeleteAll());
        methodList.add(new MyInsertAll());
        methodList.add(new MysqlInsertAllBatch());
        methodList.add(new SelectById());
        return methodList;
    }
}

注入全局注入器

   @Bean
    public MyLogicSqlInjector myLogicSqlInjector() {
        return new MyLogicSqlInjector();
    }

MybatisPlus——全局配置

总配置

mybatis-plus:
  # 【别名/类型处理器】
  type-aliases-superType: null
  type-aliases-package: null
  type-handlers-package: com.jm.config.typeHandler
  type-enums-package: null
  

  # 【sql执行器类型】
  executorType: simple
  # 【基本扫描】
  configLocation: …… #【mybatis————原生配置——xml文件】
  mapper-locations: #【mybatis————mapper扫描(,号隔开)】
  	classpath:/mapper/*Mapper.xml, /mapper/*/*Mapper.xml


  #【mybatis————原生配置——配置类】
  configuration: 
  	mapUnderscoreToCamelCase: true #驼峰命名
  	defaultEnumTypeHandler:  #枚举处理org.apache.ibatis.type.EnumTypeHandler
  	aggressiveLazyLoading: true #select懒加载
  	autoMappingBehavior: partial #
  	autoMappingUnknownColumnBehavior: NONE
  	localCacheScope: SESSION
  	cacheEnabled: true
  	configurationFactory: 
  	callSettersOnNulls: false
  configurationProperties: #【mybatis————外部配置——引入其他路径配置类】



  global-config:
	banner: true #【控制台打印sql】
	enableSqlRunner: true #【初始化SqlRunner】
    #sql阻断器
	sqlInjector: com.baomidou.mybatisplus.core.injector.DefaultSqlInjector 
	#mapper父类
	superMapperClass: com.baomidou.mybatisplus.core.mapper.Mapper.class
	#主键自增
	identifierGenerator: com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator
	#自动注入处理器
	metaObjectHandler: null
	

    # 【mybatis-plus策略配置】
    configuration:
      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #日志打印实现
      cache-enabled: false #二级缓存
    dbconfig: 
      # 【主键与互策略】
      db-type: mysql
      id-type: 2        # 【主键策略】  0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
      field-strategy: 2 # 【字段策略】  0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
      key-generator:  null
      #【驼峰命名策略】
	  map-underscore-to-camel-case: true #实体类映射驼峰命名转化
	  db-column-underline: true #数据库字段驼峰下划线转换
	  table-underline: true #表驼峰命名
	  table-prefix: null #表统一前缀
	  capital-mode: false #大写命名
	   #【格式化策略】
	  column-format: null
	  property-format: null
  	 # 【逻辑删除策略】
  	  logic-delete-field: is_delete
      logic-delete-value: 0
      logic-not-delete-value: 1
      #【自动填充策略】
      #com.baomidou.mybatisplus.annotation.FieldStrategy
	  insertStrategy: NOT_NULL
	  updateStrategy: NOT_NULL
	  selectStrategy: NOT_NULL
	  #【刷新mapper策略】
	  refresh-mapper: true # 刷新mapper 调试神器

executorType——解释

ExecutorType.SIMPLE
	该执行器类型不做特殊的事情,为每个语句的执行创建一个新的预处理语句(PreparedStatement)
ExecutorType.REUSE
	该执行器类型会复用预处理语句(PreparedStatement)
ExecutorType.BATCH
	该执行器类型会批量执行所有的更新语句

configuration——解释

autoMappingBehavior

MyBatis 自动映射策略,通过该配置可指定 MyBatis 是否并且如何来自动映射数据表字段与对象的属性,总共有 3 种可选值:
AutoMappingBehavior.NONE:不启用自动映射
AutoMappingBehavior.PARTIAL:只对非嵌套的 resultMap 进行自动映射
AutoMappingBehavior.FULL:对所有的 resultMap 都进行自动映射

autoMappingUnknownColumnBehavior

MyBatis 自动映射时未知列或未知属性处理策略,通过该配置可指定 MyBatis 在自动映射过程中遇到未知列或者未知属性时如何处理,总共有 3 种可选值:
AutoMappingUnknownColumnBehavior.NONE:不做任何处理 (默认值)
AutoMappingUnknownColumnBehavior.WARNING:以日志的形式打印相关警告信息
AutoMappingUnknownColumnBehavior.FAILING:当作映射失败处理,并抛出异常和详细信息

localCacheScope

微服务架构中需要关闭一级缓存,
原因:Service1先查询数据,若之后Service2修改了数据,之后Service1又再次以同样的查询条件查询数据,因走缓存会出现查处的数据不是最新数据

callSettersOnNulls

类型:boolean
默认值:false
即 MyBatis 在使用 resultMap 来映射查询结果中的列,如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段

你可能感兴趣的:(Java框架专题,java)