mybatis-plus 扩展批量新增的实现
作者:JOEY 发布时间:2023-07-14 14:24:13
标签:mybatis-plus,批量,新增
前言
最近发现公司的微服务项目中没有统一的批量新增方法,公司用的是MP插件,遇到批量新增都是单独去去编写xml实现,费时费力,而MP自带的批插方法只是实现了分批条sql,跟真正意义上一条sql实现批插还是有很大的性能差异,所以决定实现一个统一的批插方法。
一、MP如何扩展批量新增方法?
MP给我们预留了一个可以真正实现批插的插件InsertBatchSomeColumn,但是只是针对mysql数据库的,我们可以参照它稍加改造扩展一个针对oracle或者其他数据库的批 * 件类,然后通过sql注入器的方式注入并初始化,就可以实现真正的批插了。
二、实现步骤
1.扩展批插类
代码如下(示例):
public class InsertBatchSomeColumnOracle extends AbstractMethod {
/**
* 字段筛选条件
*/
@Setter
@Accessors(chain = true)
private Predicate<TableFieldInfo> predicate;
@SuppressWarnings("Duplicates")
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
KeyGenerator keyGenerator = new NoKeyGenerator();
SqlMethod sqlMethod = SqlMethod.INSERT_ALL;
List<TableFieldInfo> fieldList = tableInfo.getFieldList();
String insertSqlColumn = tableInfo.getKeyInsertSqlColumn(false) +
this.filterTableFieldInfo(fieldList, predicate, TableFieldInfo::getInsertSqlColumn, EMPTY);
String tableName = tableInfo.getTableName();
String columnScript = LEFT_BRACKET + insertSqlColumn.substring(0, insertSqlColumn.length() - 1) + RIGHT_BRACKET;
String insertSqlProperty = tableInfo.getKeyInsertSqlProperty(ENTITY_DOT, false) +
this.filterTableFieldInfo(fieldList, predicate, i -> i.getInsertSqlProperty(ENTITY_DOT), EMPTY);
insertSqlProperty = " into " + tableName + columnScript + " values " + LEFT_BRACKET + insertSqlProperty.substring(0, insertSqlProperty.length() - 1) + RIGHT_BRACKET;
String batchScript = SqlScriptUtils.convertForeach(insertSqlProperty, "list", null, ENTITY, EMPTY);
String keyProperty = null;
String keyColumn = null;
// 表包含主键处理逻辑,如果不包含主键当普通字段处理
if (tableInfo.havePK()) {
if (tableInfo.getIdType() == IdType.AUTO) {
/* 自增主键 */
keyGenerator = new Jdbc3KeyGenerator();
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
} else {
if (null != tableInfo.getKeySequence()) {
keyGenerator = TableInfoHelper.genKeyGenerator(getMethod(), tableInfo, builderAssistant);
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
}
}
}
String sql = String.format(sqlMethod.getSql(), batchScript);
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return this.addInsertMappedStatement(mapperClass, modelClass, getMethod(), sqlSource, keyGenerator, keyProperty, keyColumn);
}
public String getMethod() {
// 自定义 mapper 方法名
return "insertBatchSomeColumnOracle";
}
}
2.编写sql注入器
代码如下(示例):
public class MpSqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
// 防止父类的方法不可使用
List<AbstractMethod> methodList = super.getMethodList(mapperClass);
// 添加批量插入的方法
methodList.add(new InsertBatchSomeColumn());
methodList.add(new InsertBatchSomeColumnOracle());
return methodList;
}
}
3.spring容器中实例化sql注入器
代码如下(示例):
@Bean
public MpSqlInjector mpSqlInjector() {
return new MpSqlInjector();
}
4.业务代码实现
代码如下(示例):
public interface MyBaseMapper<T> extends BaseMapper<T> {
/**
* 批量插入 (mysql)
* @param entityList 实体列表
* @return 影响行数
*/
int insertBatchSomeColumn(Collection<T> entityList);
/**
* 批量插入 (oracle)
* @param entityList 实体列表
* @return 影响行数
*/
int insertBatchSomeColumnOracle(Collection<T> entityList);
}
/**
* 批量插入记录(选择字段,策略插入)
*
* @param entityList 实体对象集合
*/
public void saveBatch(Collection<T> entityList) {
if (DEFAULT_MUST_SAVE_BATCH) {
ServiceAssert.isTrue(CollectionUtil.isNotEmpty(entityList), "批量插入传入空集合, 插入失败");
}
if (CollectionUtil.isEmpty(entityList)) {
return;
}
int res;
if (DATABASE_TYPE_ORACLE.equalsIgnoreCase(dbType)) {
res = getBaseMapper().insertBatchSomeColumnOracle(entityList);
} else {
res = getBaseMapper().insertBatchSomeColumn(entityList);
}
ServiceAssert.isTrue(res == entityList.size(), "插入失败,请联系管理员");
}
/**
* 批量插入记录(选择字段,策略插入)
*
* @param entityList 实体对象集合
* @param batchSize 每批次插入数
*/
public void saveBatch(Collection<T> entityList, int batchSize) {
if (DEFAULT_MUST_SAVE_BATCH) {
ServiceAssert.isTrue(CollectionUtil.isNotEmpty(entityList), "批量插入传入空集合, 插入失败");
}
if (CollectionUtil.isEmpty(entityList)) {
return;
}
int size = entityList.size();
int idxLimit = Math.min(batchSize, size);
int i = 1;
//保存单批提交的数据集合
List<T> batchList = new ArrayList<>();
for(Iterator<T> it = entityList.iterator(); it.hasNext(); ++i) {
T element = it.next();
batchList.add(element);
int res;
if (i == idxLimit) {
if (DATABASE_TYPE_ORACLE.equalsIgnoreCase(dbType)) {
res = getBaseMapper().insertBatchSomeColumnOracle(batchList);
} else {
res = getBaseMapper().insertBatchSomeColumn(batchList);
}
//每次提交后需要清空集合数据
batchList.clear();
idxLimit = Math.min(idxLimit + batchSize, size);
ServiceAssert.isTrue(res == entityList.size(), "插入失败,请联系管理员");
}
}
}
来源:https://blog.csdn.net/qq_16277905/article/details/128299388


猜你喜欢
- 前言上一篇讲了普通轮询、加权轮询的两种实现方式,重点讲了平滑加权轮询算法,并在文末留下了悬念:节点出现分配失败时降低有效权重值;成功时提高有
- JSR303 是一套 JavaBean 参数校验的标准1、pom导入依赖<dependency><groupId>o
- 要求环境信息:WIN2008SERVER 开发工具:VS2015 开发语言:C#要求: 1.点击同步数据后接口获取数
- 本文实例为大家分享了Java实现置换密码加密解密,供大家参考,具体内容如下思路置换密码只不过是简单的换位而已,这里写的是一个分组长度为7的置
- 前言是否会遇到这样的场景,你向线程池提交了多个任务,你希望这批任务全部完成后能够反向通知你。你可能会使用线程计数的方式,等到计数器累加到提交
- 本文实例为大家分享了C#强制转换和尝试转换的方法,供大家参考,具体内容如下将String[]类型的Object类型,转换为String[]类
- 当我们在页面上进行selenium.type()或者selenium.click()操作的时候,往往需要需要等待一个元素的出现,对于一般的网
- @TransactionalEventListener监听事务项目背景最近在项目遇到一个问题A方法体内有 INSERT、UPDATE或者DE
- mybatis-plus的代码生成器会在实体类中生成数据库所有字段,我们去用mapper接口查询时,会返回数据库所有的字段。但有些字段不是我
- 应用的配置源通常都是远端的Config Server服务器,默认情况下,本地的配置优先级低于远端配置仓库。如果想实现本地应用的系统变量和co
- 在实际项目中,在处理较大的文件时,常常将文件拆分为多个子文件进行处理,最后再合并这些子文件。下面就为各位介绍下Java中合并多个文件的方法。
- 在开发 Web 项目的时候,经常需要过滤器来处理一些请求,包括字符集转换什么的,记录请求日志什么的等等。在之前的 Web 开发中,我们习惯把
- 开发环境JDK1.8 eclipse struts2-2.3.31 1.创建web项目 2.导入struts2核心jar包 3.更改web.
- 参数设置java程序启动参数 -D是用来做什么的呢? 官方解释如下:Set a system property value. If valu
- 本文实例讲述了基于WebClient实现Http协议的Post与Get对网站进行模拟登陆和浏览的方法。分享给大家供大家参考。具体分析如下:一
- IDEA全局替换通过快捷键 Ctrl+Shift+r 或这点击 Edit 》Find 》Replace In Path有些IDEA版本按了快
- 本文实例讲述了C#在RichTextBox中显示不同颜色文字的方法。分享给大家供大家参考。具体实现方法如下:#region 日志记录、支持其
- 360首页搜索效果如下1、完成编写的schoolnet校园网主要目录结构如下主要实现支持中文、拼音首字母、拼音全字母的智能搜索和换肤页面效果
- MyBatis注解实现动态SQL在 Mybatis 中,使用注解可以很方便的进行sql操作,但很多动态 SQL 都是由 xml 配置实现的。
- 效果图:为了使图片浏览器左右无限循环滑动 我们要自定义gallery的adapter如果要想自定义adapter首先要了解这几个方法@Ove