基于 MybatisPlus 逻辑删除开启情况下兼容多数据库实现批量插入更新通用流程实现
背景
- 项目上业务流程有大量使用
mysql
批量插入更新语法insert on duplicate update
- 由于现在公司业务需要,同时兼容达梦数据库使用,达梦数据库虽然也有类似的语法,不过使用起来也比较麻烦,生成相应的
SQL
可以看我这一篇文章
核心问题
MySQL
更新插入流程如何使用实现?- 如何实现多个数据库兼容插入更新的流程?
- 如何编写工具类优雅实现插入通用流程封装以及整合
MybatisPlus
lambda
表达式查询,达到方便易用的效果? - 开启
MybatisPlus
逻辑删除功能,怎么通过自定义SQL
查询出所有数据(插入更新流程可能涉及到所有的数据,并不是只是处理未逻辑删除的数据)? - 批量数据插入更新速度如何优化?
代码实现
实现多数据库兼容插入更新操作,只能根据 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;
}
}
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);
}
}
注入不带逻辑删除自定义 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;
}
}
封装自定义 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.