• 基于 MybatisPlus 逻辑删除开启情况下兼容多数据库实现批量插入更新通用流程实现


    基于 MybatisPlus 逻辑删除开启情况下兼容多数据库实现批量插入更新通用流程实现

    背景

    • 项目上业务流程有大量使用 mysql 批量插入更新语法 insert on duplicate update
    • 由于现在公司业务需要,同时兼容达梦数据库使用,达梦数据库虽然也有类似的语法,不过使用起来也比较麻烦,生成相应的 SQL 可以看我这一篇文章

    核心问题

    1. MySQL 更新插入流程如何使用实现?
    2. 如何实现多个数据库兼容插入更新的流程?
    3. 如何编写工具类优雅实现插入通用流程封装以及整合 MybatisPlus lambda 表达式查询,达到方便易用的效果?
    4. 开启 MybatisPlus 逻辑删除功能,怎么通过自定义 SQL 查询出所有数据(插入更新流程可能涉及到所有的数据,并不是只是处理未逻辑删除的数据)?
    5. 批量数据插入更新速度如何优化?

    代码实现

    实现多数据库兼容插入更新操作,只能根据 MySQL 插入更新原理利用代码抽象通用化流程,较好的通用化方式是使用 MybatisPlus 自带的通用 CRUD 逻辑方法实现,但是原有自带方法开启逻辑删除功能以后,查询方法都会自带过滤逻辑删除的数据,需要实现自定义 SQL 注入器,为了实现一套不带逻辑删除的通用方法

    拓展自定义 SQL 注入器实现

    新增自定义方法

    SelectList 方法不带逻辑删除

    public class SelectListWithoutLogicDelete extends AbstractMethod {
       
    
        @Override
        public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
       
            String sql = String.format(
                    SqlMethod.SELECT_LIST.getSql(),
                    sqlFirst(),
                    sqlSelectColumns(tableInfo, true),
                    tableInfo.getTableName(),
                    sqlWhereEntityWrapper(true, tableInfo),
                    sqlComment()
            );
    
            SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
    
            String mapperMethodName = StrUtil.lowerFirst(getClass().getSimpleName());
            return addSelectMappedStatementForTable(mapperClass, mapperMethodName, sqlSource, tableInfo);
        }
    
        // 重写 sqlWhereEntityWrapper ,去掉逻辑删除相关代码
        @Override
        protected String sqlWhereEntityWrapper(boolean newLine, TableInfo table) {
       
            String sqlScript = table.getAllSqlWhere(false, true, WRAPPER_ENTITY_DOT);
            sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", WRAPPER_ENTITY), true);
            sqlScript += NEWLINE;
            sqlScript += SqlScriptUtils.convertIf(String.format(SqlScriptUtils.convertIf(" AND", String.format("%s and %s", WRAPPER_NONEMPTYOFENTITY, WRAPPER_NONEMPTYOFNORMAL), false) + " ${%s}", WRAPPER_SQLSEGMENT),
                    String.format("%s != null and %s != '' and %s", WRAPPER_SQLSEGMENT, WRAPPER_SQLSEGMENT,
                            WRAPPER_NONEMPTYOFWHERE), true);
            sqlScript = SqlScriptUtils.convertWhere(sqlScript) + NEWLINE;
            sqlScript += SqlScriptUtils.convertIf(String.format(" ${%s}", WRAPPER_SQLSEGMENT),
                    String.format("%s != null and %s != '' and %s", WRAPPER_SQLSEGMENT, WRAPPER_SQLSEGMENT,
                            WRAPPER_EMPTYOFWHERE), true);
            sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", WRAPPER), true);
            return newLine ? NEWLINE + sqlScript : sqlScript;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    UpdateById 方法不带逻辑删除

    public class UpdateByIdWithoutLogicDelete extends AbstractMethod {
       
        @Override
        public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
       
            SqlMethod sqlMethod = SqlMethod.UPDATE_BY_ID;
    
            final String additional = optlockVersion(tableInfo);
            String sql = String.format(
                    sqlMethod.getSql(),
                    tableInfo.getTableName(),
                    // 搬运 UpdateById 代码,第一个参数变化了
                    sqlSet(false, false, tableInfo, false, ENTITY, ENTITY_DOT),
                    tableInfo.getKeyColumn(),
                    ENTITY_DOT + tableInfo.getKeyProperty(),
                    additional
            );
    
            SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
            String mapperMethodName = StrUtil.lowerFirst(getClass().getSimpleName());
            return addUpdateMappedStatement(mapperClass, modelClass, mapperMethodName, sqlSource);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    注入不带逻辑删除自定义 mapper 方法
    public class SqlInjectorExtension extends DefaultSqlInjector {
       
        @Override
        public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
       
            List<AbstractMethod> methods = super.getMethodList(mapperClass);
            // 原来基础上注入两个新方法
            methods.add(new SelectListWithoutLogicDelete());
            methods.add(new UpdateByIdWithoutLogicDelete());
            return methods;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    封装自定义 mapper

    import com.baomidou.mybatisplus.core.conditions.Wrapper;
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.baomidou.mybatisplus.core.toolkit.Constants;
    import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
    import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
    import com.baomidou.
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    idea全局搜索
    react组件
    Swift编写爬取商品详情页面的爬虫程序
    log4j漏洞CVE-2021-44228复现-排雷篇
    创新创业理论研究与实践杂志社创新创业理论研究与实践编辑部2022年第18期目录
    电子检索实体书「GitHub 热点速览 v.22.12」
    实时冷链监测——改进冷链物流技术,提高效率并降低成本
    操作系统篇之虚拟内存
    Go 语言的垃圾回收机制:自动化内存管理
    java计算机毕业设计-学生宿舍故障报修管理信息系统-源码+数据库+系统+lw文档+mybatis+运行部署
  • 原文地址:https://blog.csdn.net/hdfg159/article/details/126692713