一.如何使用
1.背景
mybatis-plus自带的方法中没有批量插入,需要通过配置文件使其生效.
2.配置文件
2.1 创建一个批量插入器
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import java.util.List;
public class InsertBatchSqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
// super.getMethodList() 保留 Mybatis Plus 自带的方法
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
// 添加自定义方法:批量插入,方法名为 insertBatchSomeColumn
// bean mapper中的方法名也是insertBatchSomeColumn 须和内部定义好的方法名保持一致。
methodList.add(new InsertBatchSomeColumn());
return methodList;
}
}
2.2 在mybatis-plus配置类中注入bean
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
/**
* 批量插入配置
* @return
*/
@Bean
public InsertBatchSqlInjector insertBatchSqlInjector() {
return new InsertBatchSqlInjector();
}
}
3.使用
3.1 在bean的mapper中生成此方法
public interface ProductDetailsMapper extends BaseMapper<ProductDetails> {
int insertBatchSomeColumn(@Param("list") List<ProductDetails> target);
}
3.2 在service中直接调用即可
int num = productDetailsMapper.insertBatchSomeColumn(productDetailsList);
二.问题
1.问题
使用此方法会遇到,批量插入时,无法使用数据库预先设置好的默认值,程序内部会报 column 'xxx' cannot be null .
2.解决方法
2.1创建一个批量插入配置类
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 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;
/**
* 增强版的批量插入,解决批量插入null 属性不能使用默认值的问题
*
* @see com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn
*/
@SuppressWarnings("serial")
public class InsertBatchSomeColumn extends AbstractMethod {
/**
* 字段筛选条件
*/
private Predicate<TableFieldInfo> predicate;
/**
* @param methodName 方法名
* @since 3.5.0
*/
protected InsertBatchSomeColumn(String methodName) {
super(methodName);
}
public String getMethod(SqlMethod sqlMethod) {
// 自定义 mapper 方法名
return methodName;
}
@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 -> getInsertSqlProperty(i,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(getMethod(sqlMethod), 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);
return this.addInsertMappedStatement(mapperClass, modelClass, getMethod(sqlMethod), sqlSource, keyGenerator, keyProperty, keyColumn);
}
public InsertBatchSomeColumn setPredicate(final Predicate<TableFieldInfo> predicate) {
this.predicate = predicate;
return this;
}
private String getInsertSqlProperty(TableFieldInfo tableFieldInfo,final String prefix) {
String newPrefix = prefix == null ? "" : prefix;
String elPart = SqlScriptUtils.safeParam(newPrefix + tableFieldInfo.getEl());
//属性为空时使用默认值
String result = SqlScriptUtils.convertIf(elPart,
String.format("%s != null", newPrefix + tableFieldInfo.getEl()),false)
+ SqlScriptUtils.convertIf("default",
String.format("%s == null", newPrefix + tableFieldInfo.getEl()),false);
return result + ",";
}
}
2.2 将批量插入器修改以适用配置类,即可正常使用
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import java.util.List;
public class InsertBatchSqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
// super.getMethodList() 保留 Mybatis Plus 自带的方法
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
// 添加自定义方法:批量插入,方法名为 insertBatchSomeColumn
// bean mapper中的方法名也是insertBatchSomeColumn 须和内部定义好的方法名保持一致。
methodList.add(new InsertBatchSomeColumn("insertBatchSomeColumn"));
//使用原版的会使数据库中已经设置默认值的字段不生效
// methodList.add(new InsertBatchSomeColumn());
return methodList;
}
}