提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
Mybatis plus 的批量插入方法saveBatch或者批量更新方法updateBatch,批量新增其实它是一个伪批量新增方法和更新方法,打印SQL日志的时候,我们可以发现它还是一条条执行insert语句的。今天带大家在 Mybatis Plus 中,实现 MySQL 真实的批量新增,即insert(…) values(xx,x),(xx,x);而不是伪批量新增
一、mysql的批量新增是什么?
MySQL 支持一条 SQL 语句可以批量插入多条记录,格式如下:
INSERT INTO t_user (name, age, gender) VALUES (‘xx’, 0, 1), (‘yy’, 0, 1), (‘zz’, 0, 1);
和常规的 INSERT 语句不同的是,VALUES 支持多条记录,通过 , 逗号隔开。这样,可以实现一次性插入多条记录。
数据量不多的情况下,常规 INSERT 和批量插入性能差距不大,但是,一旦数量级上去后,执行耗时差距就拉开了,
使用这种新增方式要比一条条的插入快很多。
二、使用步骤
先新建一个Spring boot项目,完成基本的相关配置,项目的基本结构:

1.引入mybatisplus的pom依赖,该案例使用的mybatis plus版本为3.5.7
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.5.7</version>
</dependency>
<!-- mybatis-plus 依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.7</version>
</dependency>
<!-- mybatis-plus 代码生成器依赖 -->
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-generator -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- freemarker 依赖,用于代码生成 -->
<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
2.Spring Boot的yml配置

3.编写自定义insert和update的SQL 批量处理方法
insert
package com.example.ftserver.plugin;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import java.util.List;
import java.util.function.Predicate;
/**
* @author aaa
* @date 2023-09-27 18:27
* @description
*/
public class InsertBatchColumn extends AbstractMethod {
/**
* 字段筛选条件
*/
@Setter
@Accessors(chain = true)
private Predicate<TableFieldInfo> predicate;
public InsertBatchColumn() {
super("insertBatch");
}
public InsertBatchColumn(Predicate<TableFieldInfo> predicate) {
// 此处的名称必须与后续的RootMapper的新增方法名称一致
super("insertBatch");
this.predicate = predicate;
}
@SuppressWarnings("Duplicates")
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;
SqlMethod sqlMethod = SqlMethod.INSERT_ONE;
List<TableFieldInfo> fieldList = tableInfo.getFieldList();
String insertSqlColumn = tableInfo.getKeyInsertSqlColumn(true,false) +
this.filterTableFieldInfo(fieldList, predicate, TableFieldInfo::getInsertSqlColumn, EMPTY);
String columnScript = LEFT_BRACKET + insertSqlColumn.substring(0, insertSqlColumn.length() - 1) + RIGHT_BRACKET;
String insertSqlProperty = tableInfo.getKeyInsertSqlProperty(true,ENTITY_DOT, false) +
this.filterTableFieldInfo(fieldList, predicate, i -> i.getInsertSqlProperty(ENTITY_DOT), EMPTY);
insertSqlProperty = LEFT_BRACKET + insertSqlProperty.substring(0, insertSqlProperty.length() - 1) + RIGHT_BRACKET;
String valuesScript = SqlScriptUtils.convertForeach(insertSqlProperty, "list", null, ENTITY, COMMA);
String keyProperty = null;
String keyColumn = null;
// 表包含主键处理逻辑,如果不包含主键当普通字段处理
if (tableInfo.havePK()) {
if (tableInfo.getIdType() == IdType.AUTO) {
/* 自增主键 */
keyGenerator = Jdbc3KeyGenerator.INSTANCE;
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
} else {
if (null != tableInfo.getKeySequence()) {
keyGenerator = TableInfoHelper.genKeyGenerator(modelClass.getName(), tableInfo, builderAssistant);
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
}
}
}
String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), columnScript, valuesScript);
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
// 注意第三个参数,需要与后续的RootMapper里面新增方法名称要一致,不然会报无法绑定异常
return this.addInsertMappedStatement(mapperClass, modelClass, "insertBatch", sqlSource, keyGenerator, keyProperty, keyColumn);
}
}
update
package com.example.ftserver.plugin;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
/**
* @author aaa
* @date 2023-09
* @description
*/
public class UpdateBatchColumn extends AbstractMethod {
/**
* @param methodName 方法名
* @since 3.5.0
*/
public UpdateBatchColumn(String methodName) {
super(methodName);
}
@SuppressWarnings("Duplicates")
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
String sql = "<script>\n<foreach collection=\"list\" item=\"item\" separator=\";\">\nupdate %s %s where %s=#{%s} %s\n</foreach>\n</script>";
String additional = tableInfo.isWithVersion() ? tableInfo.getVersionFieldInfo().getVersionOli("item", "item.") : "" + tableInfo.getLogicDeleteSql(true, true);
String setSql = sqlSet(tableInfo.isWithLogicDelete(), false, tableInfo, false, "item", "item.");
String sqlResult = String.format(sql, tableInfo.getTableName(), setSql, tableInfo.getKeyColumn(), "item." + tableInfo.getKeyProperty(), additional);
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
// 第三个参数必须和RootMapper的自定义方法名一致
return this.addUpdateMappedStatement(mapperClass, modelClass, "updateBatch", sqlSource);
}
}
4. 创建一个 SQL 注入器 InsertBatchSqlInjector
package com.example.ftserver.config;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.example.ftserver.plugin.InsertBatchColumn;
import com.example.ftserver.plugin.UpdateBatchColumn;
import java.util.List;
/**
* @author aaa
* @description
*/
public class CustomizedSqlInjector extends DefaultSqlInjector {
// 3.5.7中,该方法已经被废弃,使用新的getMethodList方法
/* public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methods = super.getMethodList(mapperClass,tableInfo);
// 自定义的insert SQL注入器
methods.add(new InsertBatchColumn());
// 自定义的update SQL注入器,参数需要与RootMapper的批量update名称一致
methods.add(new UpdateBatchColumn("updateBatch"));
return methods;
}*/
public List<AbstractMethod> getMethodList(Configuration configuration, Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methods = super.getMethodList(configuration, mapperClass, tableInfo);
// 自定义的insert SQL注入器
methods.add(new InsertBatchColumn());
// 自定义的update SQL注入器,参数需要与RootMapper的批量update名称一致
methods.add(new UpdateBatchColumn("updateBatch"));
return methods;
}
}
5.将SQL 注入器放入配置类
package com.example.ftserver.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author aaa
* @description
*/
@Configuration
@MapperScan(basePackages = "com.example.ftserver.mapper") // 不用配置.*
public class MybatisPlusConfig {
@Bean
public CustomizedSqlInjector sqlInjector(){
return new CustomizedSqlInjector();
}
/**
* 添加分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加
return interceptor;
}
}
6.新建一个在 config 包下创建 RootMapper 接口,让其继承自 Mybatis Plus 提供的 BaseMapper, 并定义批量插入方法。注意:BaseMapper中的所有方法需要重写,不然调用时可能会报空指针异常
package com.example.ftserver.plugin;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
/**
* @author aaa
* @date 2023-09-28 16:11
* @description
*/
public interface RootMapper<T> extends BaseMapper<T> {
/**
* 自定义批量新增,代替mybatis plus 自带的批量新增
*
* @param batchList 批量新增参数
* @return int
*/
int insertBatch(@Param("list") Collection<T> batchList);
/**
* 根据id批量修改
*
* @param batchList 批量更新参数
* @return int
*/
int updateBatch(@Param("list") Collection<T> batchList);
@Override
int insert(T entity);
/**
* 根据 ID 删除
*
* @param id 主键ID
*/
@Override
default int deleteById(Serializable id) {
return deleteById(id, true);
}
/**
* 根据 ID 删除
*
* @param useFill 是否填充
* @param obj 主键ID或实体
* @since 3.5.7
*/
@Override
default int deleteById(Object obj, boolean useFill) {
return BaseMapper.super.deleteById(obj, useFill);
}
/**
* 根据实体(ID)删除
*
* @param entity 实体对象
* @since 3.4.4
*/
@Override
int deleteById(T entity);
/**
* 根据 columnMap 条件,删除记录
*
* @param columnMap 表字段 map 对象
*/
@Override
default int deleteByMap(Map<String, Object> columnMap) {
return this.delete(Wrappers.<T>query().allEq(columnMap));
}
/**
* 根据 entity 条件,删除记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
*/
@Override
int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 删除(根据ID或实体 批量删除)
*
* @param idList 主键ID列表或实体列表(不能为 null 以及 empty)
* @since 3.5.7
*/
@Override
default int deleteByIds(@Param(Constants.COLL) Collection<?> idList) {
return deleteByIds(idList, true);
}
/**
* 删除(根据ID或实体 批量删除)
* <p>
* 普通删除: DELETE FROM h2user WHERE id IN ( ? , ? )
* </p>
* <p>
* 逻辑删除: UPDATE h2user SET deleted=1 WHERE id IN ( ? , ? ) AND deleted=0
* </p>
* <p>
* 逻辑删除(填充): UPDATE h2user SET delete_user = 'xxx', deleted=1 WHERE id IN ( ? , ? ) AND deleted=0
* <ul>注意:无论参数为id还是实体,填充参数只会以方法追加的et参数为准.<ul/>
* </p>
*
* @param collections 主键ID列表或实体列表(不能为 null 以及 empty)
* @param useFill 逻辑删除下是否填充
* @since 3.5.7
*/
@Override
default int deleteByIds(@Param(Constants.COLL) Collection<?> collections, boolean useFill) {
return BaseMapper.super.deleteByIds(collections, useFill);
}
/**
* 根据 ID 修改
*
* @param entity 实体对象
*/
@Override
int updateById(@Param(Constants.ENTITY) T entity);
/**
* 根据 whereEntity 条件,更新记录
*
* @param entity 实体对象 (set 条件值,可以为 null,当entity为null时,无法进行自动填充)
* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
*/
@Override
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
/**
* 根据 Wrapper 更新记录
* <p>此方法无法进行自动填充,如需自动填充请使用{@link #update(Object, Wrapper)}</p>
*
* @param updateWrapper {@link UpdateWrapper} or {@link LambdaUpdateWrapper}
* @since 3.5.4
*/
@Override
default int update(@Param(Constants.WRAPPER) Wrapper<T> updateWrapper) {
return update(null, updateWrapper);
}
/**
* 根据 ID 查询
*
* @param id 主键ID
*/
@Override
T selectById(Serializable id);
/**
* 查询(根据ID 批量查询)
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
@Override
List<T> selectBatchIds(@Param(Constants.COLL) Collection<? extends Serializable> idList);
/**
* 查询(根据ID 批量查询)
*
* @param idList idList 主键ID列表(不能为 null 以及 empty)
* @param resultHandler resultHandler 结果处理器 {@link ResultHandler}
* @since 3.5.4
*/
@Override
void selectBatchIds(@Param(Constants.COLL) Collection<? extends Serializable> idList, ResultHandler<T> resultHandler);
/**
* 查询(根据 columnMap 条件)
*
* @param columnMap 表字段 map 对象
*/
@Override
default List<T> selectByMap(Map<String, Object> columnMap) {
return this.selectList(Wrappers.<T>query().allEq(columnMap));
}
/**
* 查询(根据 columnMap 条件)
*
* @param columnMap 表字段 map 对象
* @param resultHandler resultHandler 结果处理器 {@link ResultHandler}
* @since 3.5.4
*/
default void selectByMap(Map<String, Object> columnMap, ResultHandler<T> resultHandler) {
this.selectList(Wrappers.<T>query().allEq(columnMap), resultHandler);
}
/**
* 根据 entity 条件,查询一条记录
* <p>查询一条记录,例如 qw.last("limit 1") 限制取一条记录, 注意:多条数据会报异常</p>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
default T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper) {
return this.selectOne(queryWrapper, true);
}
/**
* 根据 entity 条件,查询一条记录,现在会根据{@code throwEx}参数判断是否抛出异常,如果为false就直接返回一条数据
* <p>查询一条记录,例如 qw.last("limit 1") 限制取一条记录, 注意:多条数据会报异常</p>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
* @param throwEx boolean 参数,为true如果存在多个结果直接抛出异常
*/
default T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper, boolean throwEx) {
return BaseMapper.super.selectOne(queryWrapper, true);
}
/**
* 根据 Wrapper 条件,判断是否存在记录
*
* @param queryWrapper 实体对象封装操作类
* @return 是否存在记录
*/
default boolean exists(Wrapper<T> queryWrapper) {
Long count = this.selectCount(queryWrapper);
return null != count && count > 0;
}
/**
* 根据 Wrapper 条件,查询总记录数
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
Long selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 entity 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 entity 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
* @param resultHandler 结果处理器 {@link ResultHandler}
* @since 3.5.4
*/
void selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper, ResultHandler<T> resultHandler);
/**
* 根据 entity 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件
* @param queryWrapper 实体对象封装操作类(可以为 null)
* @since 3.5.3.2
*/
List<T> selectList(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 entity 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件
* @param queryWrapper 实体对象封装操作类(可以为 null)
* @param resultHandler 结果处理器 {@link ResultHandler}
* @since 3.5.4
*/
void selectList(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper, ResultHandler<T> resultHandler);
/**
* 根据 Wrapper 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类
*/
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类
* @param resultHandler 结果处理器 {@link ResultHandler}
* @since 3.5.4
*/
void selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper, ResultHandler<Map<String, Object>> resultHandler);
/**
* 根据 Wrapper 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件
* @param queryWrapper 实体对象封装操作类
* @since 3.5.3.2
*/
List<Map<String, Object>> selectMaps(IPage<? extends Map<String, Object>> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件
* @param queryWrapper 实体对象封装操作类
* @param resultHandler 结果处理器 {@link ResultHandler}
* @since 3.5.4
*/
void selectMaps(IPage<? extends Map<String, Object>> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper, ResultHandler<Map<String, Object>> resultHandler);
/**
* 根据 Wrapper 条件,查询全部记录
* <p>注意: 只返回第一个字段的值</p>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
<E> List<E> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录
* <p>注意: 只返回第一个字段的值</p>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
* @param resultHandler 结果处理器 {@link ResultHandler}
* @since 3.5.4
*/
<E> void selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper, ResultHandler<E> resultHandler);
/**
* 根据 entity 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
default <P extends IPage<T>> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper) {
return BaseMapper.super.selectPage(page, queryWrapper);
}
/**
* 根据 Wrapper 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件
* @param queryWrapper 实体对象封装操作类
*/
default <P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper) {
return BaseMapper.super.selectMapsPage(page, queryWrapper);
}
/**
* 主键存在更新记录,否插入一条记录
*
* @param entity 实体对象 (不能为空)
* @since 3.5.7
*/
default boolean insertOrUpdate(T entity) {
return BaseMapper.super.insertOrUpdate(entity);
}
/**
* 插入(批量)
*
* @param entityList 实体对象集合
* @since 3.5.7
*/
default List<BatchResult> insert(Collection<T> entityList) {
return insert(entityList, Constants.DEFAULT_BATCH_SIZE);
}
/**
* 插入(批量)
*
* @param entityList 实体对象集合
* @param batchSize 插入批次数量
* @since 3.5.7
*/
default List<BatchResult> insert(Collection<T> entityList, int batchSize) {
return BaseMapper.super.insert(entityList, batchSize);
}
/**
* 根据ID 批量更新
*
* @param entityList 实体对象集合
* @since 3.5.7
*/
default List<BatchResult> updateById(Collection<T> entityList) {
return updateById(entityList, Constants.DEFAULT_BATCH_SIZE);
}
/**
* 根据ID 批量更新
*
* @param entityList 实体对象集合
* @param batchSize 插入批次数量
* @since 3.5.7
*/
default List<BatchResult> updateById(Collection<T> entityList, int batchSize) {
return BaseMapper.super.updateById(entityList, batchSize);
}
/**
* 批量修改或插入
*
* @param entityList 实体对象集合
* @since 3.5.7
*/
default List<BatchResult> insertOrUpdate(Collection<T> entityList) {
return insertOrUpdate(entityList, Constants.DEFAULT_BATCH_SIZE);
}
/**
* 批量修改或插入
*
* @param entityList 实体对象集合
* @param batchSize 插入批次数量
* @since 3.5.7
*/
default List<BatchResult> insertOrUpdate(Collection<T> entityList, int batchSize) {
return BaseMapper.super.insertOrUpdate(entityList, batchSize);
}
/**
* 批量修改或插入
*
* @param entityList 实体对象集合
* @since 3.5.7
*/
default List<BatchResult> insertOrUpdate(Collection<T> entityList, BiPredicate<BatchSqlSession, T> insertPredicate) {
return insertOrUpdate(entityList, insertPredicate, Constants.DEFAULT_BATCH_SIZE);
}
/**
* 批量修改或插入
*
* @param entityList 实体对象集合
* @param batchSize 插入批次数量
* @since 3.5.7
*/
default List<BatchResult> insertOrUpdate(Collection<T> entityList, BiPredicate<BatchSqlSession, T> insertPredicate, int batchSize) {
return BaseMapper.super.insertOrUpdate(entityList, insertPredicate, batchSize);
}
}
7.新建 自己的Mapper,注意继承刚刚自定义的 RootMapper, 而不是Mybatis plus的 BaseMapper :
package com.example.ftserver.mapper;
import com.test.ft.common.entity.PersonEntity;
import com.example.ftserver.plugin.RootMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author aaa
* @since 2023-10-19 16:32:39
*/
public interface PersonMapper extends RootMapper<PersonEntity> {
}
批量测试结果
自增id示例:
package com.test.ft.common.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.test.ft.common.entity.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author aaa
* @since 2023-10-19 16:32:39
*/
@Getter
@Setter
@Accessors(chain = true)
@TableName("person_t")
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "PersonEntity对象", description = "")
public class PersonEntity extends BaseEntity {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty("姓名")
@TableField("`name`")
private String name;
@ApiModelProperty("年龄")
@TableField("age")
private Integer age;
}
id为UUID示例:
package com.test.ft.common.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.test.ft.common.entity.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author tx wb
* @since 2023-10-19 16:32:38
*/
@Getter
@Setter
@Accessors(chain = true)
@TableName("company_t")
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "CompanyEntity对象", description = "")
public class CompanyEntity extends BaseEntity {
@TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id;
@TableField("company_name")
private String companyName;
@TableField("address")
private String address;
}
测试示例:
package com.example.ftserver;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.example.ftserver.mapper.CompanyMapper;
import com.example.ftserver.mapper.PersonMapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.test.ft.common.entity.CompanyEntity;
import com.test.ft.common.entity.PersonEntity;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
@SpringBootTest
@RunWith(SpringRunner.class)
class FtServerApplicationTests {
@Autowired
RestHighLevelClient client;
@Autowired
CompanyMapper companyMapper;
@Autowired
PersonMapper personMapper;
/**
* 批量新增测试
*/
@Test
public void testBatch() {
List<PersonEntity> personEntityList = Lists.newArrayList();
for (int i = 0; i < 5; i++) {
PersonEntity entity = new PersonEntity();
entity.setAge(i + 1);
String string = RandomUtil.randomString(i + 1);
if (string.length() > 10) {
string = string.substring(0, 9);
}
entity.setName(string);
personEntityList.add(entity);
}
List<CompanyEntity> companyEntityList = Lists.newArrayList();
for (int i = 0; i < 5; i++) {
CompanyEntity entity = new CompanyEntity();
String string = RandomUtil.randomString(i + 1);
if (string.length() > 10) {
string = string.substring(0, 9);
}
entity.setCompanyName(string);
string = RandomUtil.randomString(i + 1);
if (string.length() > 1000) {
string = string.substring(500, 800);
}
entity.setAddress(string);
companyEntityList.add(entity);
}
// id为非自增
companyMapper.insertBatch(companyEntityList);
// id为自增
personMapper.insertBatch(personEntityList);
}
}
/**
* 批量更新测试
*/
@Test
public void updateBatchTest() {
List<CompanyEntity> list = companyMapper.selectList(Wrappers.lambdaQuery(CompanyEntity.class));
for (CompanyEntity company : list) {
String address="cc"+RandomUtil.randomNumbers(20);
if (address.length()>1000) {
address=address.substring(500);
}
company.setAddress(address);
}
companyMapper.updateBatch(list);
}
测试结果:
insert测试结果:

update测试结果:

可以看到,已经insert和update成功
附录mybatis plus代码生成器:
可以将生成器直接放置在test目录下:

代码:
package com.example.ftserver;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.keywords.MySqlKeyWordsHandler;
import com.example.ftserver.plugin.RootMapper;
import com.test.ft.common.entity.BaseEntity;
import java.util.Collections;
/**
* @author aaa
* @date 2023-10-19 15:10
* @description
*/
public class Generator {
public static void main(String[] args) {
DataSourceConfig.Builder dataSourceConfigBuilder = new DataSourceConfig.Builder("jdbc:mysql://localhost:3306/test?useUnicode=true&autoReconnect=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false",
"root", "root").dbQuery(new MySqlQuery()).typeConvert(new MySqlTypeConvert()).keyWordsHandler(new MySqlKeyWordsHandler());
FastAutoGenerator fastAutoGenerator = FastAutoGenerator.create(dataSourceConfigBuilder);
fastAutoGenerator.globalConfig(builder ->
builder.disableOpenDir().outputDir("F:\\xx\\ft-server" + "/src/main/java").author("tb").commentDate("yyyy-MM-dd HH:mm:ss")
.dateType(DateType.TIME_PACK).enableSwagger());
fastAutoGenerator.packageConfig(c -> c.parent("com.test.ft.common.entity").entity("entity").mapper("mapper").service("service").serviceImpl("impl").controller("controller").xml("Mapper.xml")
.pathInfo(Collections.singletonMap(OutputFile.xml, "F:\\xx\\ft-server" + "\\src\\main/resources/mapper"))// 设置XML资源文件的目录
);
fastAutoGenerator.strategyConfig(s ->
s.enableCapitalMode().enableSkipView().disableSqlFilter().addInclude("company_t", "person_t").
addTableSuffix("_t") // 添加过滤表的后缀
.addTablePrefix("test_") // 添加过滤表的前缀
);
fastAutoGenerator.strategyConfig(s -> s.entityBuilder(). // 实体类设置
enableLombok(). // 启用Lombok
enableFileOverride(). // 启用文件覆盖
enableTableFieldAnnotation(). // 生成实体时生成字段的注解,包括@TableId注解等-,可以不需要
naming(NamingStrategy.underline_to_camel). // 数据库表和字段映射到实体的命名策略,为下划线转驼峰.
columnNaming(NamingStrategy.underline_to_camel).
idType(IdType.AUTO) // 全局主键类型为AUTO(自增)
.superClass(BaseEntity.class).
disableSerialVersionUID().enableChainModel().formatFileName("%sEntity"));
// controller控制器设置
fastAutoGenerator.strategyConfig(c -> c.controllerBuilder().
enableRestStyle(). // 开启生成@RestController控制器
enableHyphenStyle().formatFileName("%sController")); // 开启驼峰转连字符 localhost:8080/hello_id_2
// Service设置
fastAutoGenerator.strategyConfig(s -> s.serviceBuilder().formatServiceFileName("%sService").formatServiceImplFileName("%sServiceImpl"));
// Mapper设置
fastAutoGenerator.strategyConfig(m -> m.mapperBuilder().formatMapperFileName("%sMapper").formatXmlFileName("%sMapper").
superClass(RootMapper.class). // 设置自定义继承的Mapper
enableBaseResultMap(). // xml里面的基本<resultMap>
enableBaseColumnList()); // xml里面的基础列
// 模板引擎
fastAutoGenerator.templateEngine(new FreemarkerTemplateEngine());
fastAutoGenerator.execute();
}
}
总结
以上就是MyBatis plus对MySQL实现批量新增,批量修改的内容,才疏学浅,如有错误,希望多多的指正。需要注意的是:**该方法只对MySQL测试过,其他的数据库支持度不一致,不一定适用

关注点:
在新增后,Mybatis Plus会自动返回新增的id。但是使用该方法批量新增后,只会返回新增的最后一条数据的id,如果需要在批量新增后返回所有的id,则需要使用IService里自带的saveBatch()方法
MyBatis Plus批量新增与更新
848

被折叠的 条评论
为什么被折叠?



