MBP中yml屬性注入及邏輯刪除過程

  • 背景 : 參考這篇文章 https://www.cnblogs.com/54chensongxia/p/14247966.html 想做唯一索引并且使用MybatisPlus做邏輯刪除保證數(shù)據(jù)正常插入
    想采用的是下面一個(gè)解決方案
    解決方案

    在實(shí)現(xiàn)的過程碰到的問題 做一下匯總 logic-delete-value: null
  • 當(dāng)前使用的mbp版本是3.3.1
  • yml
# mybatis-plus
#具體默認(rèn)配置項(xiàng)參考com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties
mybatis-plus:
  #參考默認(rèn)配置項(xiàng) 可以忽略
  mapper-locations: classpath*:/mapper/**/*.xml
  #具體默認(rèn)配置項(xiàng)參考com.baomidou.mybatisplus.core.config.GlobalConfig
  global-config: 
    #具體默認(rèn)配置項(xiàng)參考com.baomidou.mybatisplus.core.config.GlobalConfig.DbConfig
    db-config:
      # 默認(rèn)配置是1 需要使用null覆蓋
      logic-delete-value: null
      # 默認(rèn)配置是0 可以忽略
      logic-not-delete-value: 0 
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    1. 注入
@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisPlusProperties.class)
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisPlusLanguageDriverAutoConfiguration.class})
public class MybatisPlusAutoConfiguration implements InitializingBean
  1. 注入MybatisPlusProperties
@Data
@Accessors(chain = true)
@ConfigurationProperties(prefix = Constants.MYBATIS_PLUS) 注意這個(gè)前綴
public class MybatisPlusProperties
部分默認(rèn)值

由此可見yml中的mapperLocations冗余


嵌套注入配置類
  1. 邏輯刪除:
  • 3.1 com.baomidou.mybatisplus.core.injector.AbstractSqlInjector#inspectInject


    inspectInject
  • 3.2 com.baomidou.mybatisplus.core.metadata.TableInfoHelper#initTableInfo


    核心方法
  • 3.3 com.baomidou.mybatisplus.core.metadata.TableInfoHelper#initTableFields


    核心方法
  • 3.4 com.baomidou.mybatisplus.core.metadata.TableFieldInfo#TableFieldInfo(com.baomidou.mybatisplus.core.config.GlobalConfig.DbConfig, com.baomidou.mybatisplus.core.metadata.TableInfo, java.lang.reflect.Field)


    核心方法
  • 3.5 com.baomidou.mybatisplus.core.metadata.TableFieldInfo#initLogicDelete


    核心方法
  • 3.6 上述3.3步驟中還有一個(gè)核心方法
    com.baomidou.mybatisplus.core.metadata.TableInfo#setFieldList


    核心方法
  void setFieldList(List<TableFieldInfo> fieldList) {
        this.fieldList = fieldList;
        fieldList.forEach(i -> {
            if (i.isLogicDelete()) {//核心方法
                this.logicDelete = true;
            }
            if (i.isWithInsertFill()) {
                this.withInsertFill = true;
            }
            if (i.isWithUpdateFill()) {
                this.withUpdateFill = true;
            }
            if (i.isVersion()) {
                this.withVersion = true;
                this.versionFieldInfo = i;
            }
        });
    }
  • 3.7 com.baomidou.mybatisplus.core.metadata.TableFieldInfo#isLogicDelete
    /**
     * 是否啟用了邏輯刪除
     */
    public boolean isLogicDelete() {
        return StringUtils.isNotBlank(logicDeleteValue) && StringUtils.isNotBlank(logicNotDeleteValue);
    }
  • 如果mybatis-plus.global-config.db-config.logic-delete-value:null 那么springboot注入得到的值是"" 需要研究下
    參考SpringBoot yml配置null坑
    所以這里判斷不是邏輯刪除 所以后續(xù)走了物理刪除
LogicDeleteByIdWithFill

debug截圖

debug stack
  • 解決方案1:
# mybatis-plus
#具體默認(rèn)配置項(xiàng)參考com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties
mybatis-plus:
  #參考默認(rèn)配置項(xiàng) 可以忽略
  mapper-locations: classpath*:/mapper/**/*.xml
  #具體默認(rèn)配置項(xiàng)參考com.baomidou.mybatisplus.core.config.GlobalConfig
  global-config:
    #具體默認(rèn)配置項(xiàng)參考com.baomidou.mybatisplus.core.config.GlobalConfig.DbConfig
    db-config:
      # 默認(rèn)配置是1 需要使用null覆蓋
      logic-delete-value: "null"
      # 默認(rèn)配置是0 可以忽略
      logic-not-delete-value: 0
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  • 這樣可以解決的原因需要參考mbp底層對(duì)于"null"的處理邏輯,代碼片段如下:
    com.baomidou.mybatisplus.core.metadata.TableInfo#formatLogicDeleteSql

/**
     * format logic delete SQL, can be overrided by subclass
     * github #1386
     *
     * @param isWhere true: logicDeleteValue, false: logicNotDeleteValue
     * @return sql
     */
    private String formatLogicDeleteSql(boolean isWhere) {
        final String value = isWhere ? logicDeleteFieldInfo.getLogicNotDeleteValue() : logicDeleteFieldInfo.getLogicDeleteValue();
        if (isWhere) {
            if (NULL.equalsIgnoreCase(value)) {
                return logicDeleteFieldInfo.getColumn() + " IS NULL";
            } else {
                return logicDeleteFieldInfo.getColumn() + EQUALS + String.format(logicDeleteFieldInfo.isCharSequence() ? "'%s'" : "%s", value);
            }
        }
        final String targetStr = logicDeleteFieldInfo.getColumn() + EQUALS;
        if (NULL.equalsIgnoreCase(value)) {
            return targetStr + NULL;
        } else {
            return targetStr + String.format(logicDeleteFieldInfo.isCharSequence() ? "'%s'" : "%s", value);
        }
    }

tips: String NULL = "null";


  • 解決方案2:
    攔截邏輯刪除處理的語(yǔ)句:方式是重寫SystemLogicDeleteById覆蓋默認(rèn)的LogicDeleteSqlInjector
/**
 * 根據(jù) id 邏輯刪除數(shù)據(jù),并帶字段填充功能
 * <p>注意入?yún)⑹?entity !!! ,如果字段沒有自動(dòng)填充,就只是單純的邏輯刪除</p>
 * <p>
 * 自己的通用 mapper 如下使用:
 * <pre>
 * int deleteByIdWithFill(T entity);
 * </pre>
 * </p>
 *
 * @author miemie
 * @since 2018-11-09
 */
public class SystemLogicDeleteById extends AbstractMethod {

  @Override
  public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
    String sql;
    SqlMethod sqlMethod = SqlMethod.LOGIC_DELETE_BY_ID;
    if (tableInfo.isLogicDelete()) {
      List<TableFieldInfo> fieldInfos = tableInfo.getFieldList().stream()
          .filter(TableFieldInfo::isWithUpdateFill)
          .collect(toList());
      if (CollectionUtils.isNotEmpty(fieldInfos)) {
        String sqlSet = "SET " + fieldInfos.stream().map(i -> i.getSqlSet(EMPTY)).collect(joining(EMPTY))
            + tableInfo.getLogicDeleteSql(false, false);
        sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), sqlSet, tableInfo.getKeyColumn(),
            tableInfo.getKeyProperty(), tableInfo.getLogicDeleteSql(true, true));
      } else {
        sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), "SET deleted=null",
            tableInfo.getKeyColumn(), tableInfo.getKeyProperty(),
            tableInfo.getLogicDeleteSql(true, true));
      }
    } else {
      sqlMethod = SqlMethod.DELETE_BY_ID;
      sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), tableInfo.getKeyColumn(),
          tableInfo.getKeyProperty());
    }
    SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
    return addUpdateMappedStatement(mapperClass, modelClass, getMethod(sqlMethod), sqlSource);
  }

  @Override
  public String getMethod(SqlMethod sqlMethod) {
    // 自定義 mapper 方法名
    return "deleteByIdWithFill";
  }
}

@Configuration
@EnableTransactionManagement
@MapperScan(basePackages = {"com.compass.msg.**.mapper"})
public class MybatisPlusConfig {

  /**
   * mybatis-plus分頁(yè)插件
   */
  @Bean
  public PaginationInterceptor paginationInterceptor() {
    PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
    //開啟 count 的 join 優(yōu)化,只針對(duì)部分 left join
    paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
    return new PaginationInterceptor();
  }

  /**
   * 樂觀鎖mybatis插件
   */
  @Bean
  public OptimisticLockerInterceptor optimisticLockerInterceptor() {
    return new OptimisticLockerInterceptor();
  }

  /**
   * 邏輯刪除sql注射器
   *
   * @return {@link LogicDeleteSqlInjector }
   * @author lvsheng
   * @date 2021/11/22 12:48
   */
  @Bean
  public LogicDeleteSqlInjector logicDeleteSqlInjector() {
    return new LogicDeleteSqlInjector();
  }



/**
 * 邏輯刪除sql注射器
 *
 * @author lvsheng
 * @version 1.0.0
 * @date 2021/11/22 12:50
 * @see DefaultSqlInjector
 */
public class LogicDeleteSqlInjector extends DefaultSqlInjector {

  @Override
  public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
    List<AbstractMethod> methodList = super.getMethodList(mapperClass);
    methodList.add(new SystemLogicDeleteById());
    return methodList;
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容