mybatis 实现动态参数批量插入

本文介绍了如何使用MyBatis通过动态参数实现批量插入操作,详细解析了mapper文件、持久化层函数的编写,以及如何利用反射工具获取实体类字段,最后展示了值集合的组装过程。核心代码包括mapper中的foreach标签和持久化层的方法定义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在实际业务开发中,为了减少代码量,实现万变不离其宗的思想,像批量插入、查询、删除等数据库操作以动态参数的方式实现,本文将阐述动态参数实现mybatis批量插入核心代码

1.mapper文件写法

    <sql id="values">
        <foreach item="item" collection="list" separator=",">
            <foreach collection="item" item="detailItem" index="index" open="("
                     close=")" separator=",">
                #{detailItem}
            </foreach>
        </foreach>
    </sql>
    <!-- 批量新增单位信息表信息 -->
    <insert id="addSalAgencys" parameterType="list">
        INSERT INTO ${tableName} (
        <foreach collection="columns" item="columnItem" separator=",">
            ${columnItem}
        </foreach>)
         VALUES
        <include refid="values"></include>
    </insert>

2.持久化层函数

    /**
     * basic sql
     * @param tableName 表名
     * @param columns 列字段集合
     * @param list 值集合
     */
    void addSalAgencys(@Param("tableName") String tableName,
                       @Param("columns") List<String> columns,
                       @Param("list") List<List<Object>> list);

3.参数tableName是表名,这个没什么特别注意的,通过配置表的方式或者别的方式传入都可以,和数据库表名对应即可

columns列字段集合,直接用工具类ReflectionUtil获取就可以,工具类代码

import com.boss.bis.common.exception.BusinessException;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

public class ReflectionUtil {
    public static final char UNDERLINE = '_';
    private static final Logger log = LoggerFactory.getLogger(ReflectionUtil.class);

    public static List<Field> getFields(Class<?> clazz) {
        List<Field> fieldList = new ArrayList<>();
        fieldList.addAll(Lists.newArrayList(clazz.getDeclaredFields()));
        if (!(clazz.getSuperclass().isAssignableFrom(Object.class))) {
            fieldList.addAll(getFields(clazz.getSuperclass()));
        }
        return fieldList;
    }

    public static Field getField(String fieldName, Class<?> cls) {
        try {
            return cls.getDeclaredField(underlineToCamel(fieldName));
        } catch (NoSuchFieldException e) {
            Class<?> parentCls = cls.getSuperclass();
            if (ObjectUtils.isEmpty(parentCls)) {
                log.error(e.getMessage(), e);
                throw new BusinessException(e.getMessage());
            }
            return getField(fieldName, parentCls);
        }
    }

    public static void setValueByField(String fieldName, Object object, Object value) {
        Field field;
        try{
            field = getField(fieldName, object.getClass());
            field.setAccessible(true);
        }catch (Exception e){
            log.error("字段不存在", e);
            return;
        }

        try {
            if (BigDecimal.class.equals(field.getType())) {
                field.set(object, new BigDecimal(String.valueOf(value)));
            } else if (String.class.equals(field.getType())) {
                field.set(object, value);
            }
        } catch (IllegalAccessException e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * 下划线格式字符串转换为驼峰格式字符串
     *
     * @param param
     * @return
     */
    public static String underlineToCamel(String param) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        if (param.indexOf(UNDERLINE) < 0) {
            return param;
        }
        String paramTmp = param.toLowerCase();
        int len = paramTmp.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = paramTmp.charAt(i);
            if (c == UNDERLINE) {
                if (++i < len) {
                    sb.append(Character.toUpperCase(paramTmp.charAt(i)));
                }
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    public static Object getValueByField(String fieldName, Object object) {
        Field field;
        try{
            field = getField(fieldName, object.getClass());
            field.setAccessible(true);
        }catch (Exception e){
            log.error("字段不存在", e);
            throw new BusinessException(e.getMessage());
        }
        try {
            if (BigDecimal.class.equals(field.getType())) {
                return new BigDecimal(String.valueOf(field.get(object)));
            }
            return field.get(object);
        } catch (IllegalAccessException e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(e.getMessage());
        }
    }
}

通过ReflectionUtil.getFields获取实体类的映射字段

// 数据库字段生成
        List<Field> fields = ReflectionUtil.getFields(cls);
        List<String> underList = new ArrayList<>();
        List<String> camelList = new ArrayList<>();
        StringBuilder colsql = new StringBuilder(200);
        for (Field field : fields) {
            if(Modifier.isStatic(field.getModifiers())){
                continue;
            }
            String name = field.getName();
            String underName = BisBeanUtils.camelToUnderline(name).toUpperCase();
            if(camelList.indexOf(name) > -1){
                continue;
            }
            underList.add(underName);
            camelList.add(name);
            colsql.append(underName + " as " + name).append(", ");
        }
        colsql.delete(colsql.length() - 2, colsql.length() - 1);

这样就获取到了带下划线的字段集合underList,即columns
camelList驼峰法的字段集合,用于第4点组装值集合
colsql查询字段并起驼峰法别名,类似于stu_name as stuName, stu_age as stuAge

这样查询出来的数据用map接收,得出来的map就会是以下这样,maps
在这里插入图片描述
4.组装插入的值集合list

private List<List<Object>> buildSaveData(List<Map> maps, List<String> camelList) {
        List<List<Object>> dataList = maps.stream().map(t -> {
            List<Object> list = new ArrayList<>();
            camelList.stream().forEach(field -> {
                list.add(t.get(field));
            });
            return list;
        }).collect(Collectors.toList());
        return dataList;
    }

以上就是mybatis实现动态参数批量插入的核心代码,描述上可能比较欠缺,毕竟是一只不太会表达的程序猿,有不明白的铁子可以给我留言。
在这里插入图片描述

### MyBatis Plus 动态表名批量插入实现 #### 使用 `MetaObject` 和自定义 SQL 注入器 为了实现MyBatis Plus 中支持动态表名的批量插入功能,可以通过继承默认的 `DefaultSqlInjector` 类来创建自定义的 SQL 注入器。通过这种方式可以在运行时指定不同的表名称。 ```java public class DynamicTableSqlInjector extends DefaultSqlInjector { @Override public void injectMappedStatement(Class<?> mapperClass, MetaObject metaObj) { super.injectMappedStatement(mapperClass, metaObj); // 获取Mapper接口上的注解信息或其他配置项 String tableName = getDynamicTableName(metaObj); AbstractMethod batchInsert = new InsertBatchSomeColumn() { @Override public MappedStatement injectMapStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) { return this.batchInsertCustom(tableInfo, tableName); } private MappedStatement batchInsertCustom(TableInfo tableInfo, String customTableName){ // 自定义逻辑处理... return null; } }; batchInsert.setEntityTable(new EntityTable(customTableName)); batchInsert.argTypeList.add(Object.class); batchInsert.inject(this.configuration, mapperClass, method.getName(), argClassArray); } protected abstract String getDynamicTableName(MetaObject metaObj); } ``` 此代码片段展示了如何扩展默认的 SQL 注入机制以适应特定需求[^3]。 #### Mapper 接口设计 对于希望使用该特性的 DAO 层接口,则需遵循如下模式: ```java @SelectProvider(type=BaseMapperProvider.class,method="dynamicTableBatchInsert") public int dynamicTableBatchInsert(@Param("list") List<YourEntity> list,@Param("tableName")String tableName); ``` 这里假设有一个名为 `BaseMapperProvider` 的类负责生成实际执行的 SQL 语句,并接收两个参数——实体列表和目标表的名字。 #### XML 或者 Java 方法内联方式构建 SQL 如果采用 XML 方式编写映射文件的话,那么可以像下面这样写: ```xml <mapper namespace="com.example.mapper.YourMapper"> <!-- ... --> <select id="dynamicTableBatchInsert" parameterType="map" resultType="_int"> INSERT INTO ${tableName} (${columnNames}) VALUES <foreach collection="list" item="item" separator=","> (#{item.propertyName1}, #{item.propertyName2}) <!-- 替换成真实的字段 --> </foreach> </select> </mapper> ``` 或者直接在 Provider 类里拼接字符串形式返回完整的 SQL 文本: ```java class BaseMapperProvider { public String dynamicTableBatchInsert(Map<String,Object> params){ StringBuilder sqlBuilder=new StringBuilder(); List<YourEntity> entityList=(List<YourEntity>)params.get("list"); String targetTableName=params.getString("tableName"); sqlBuilder.append("INSERT INTO ").append(targetTableName).append("(col1,col2,...)"); sqlBuilder.append("VALUES "); for(int i=0;i<entityList.size();i++){ YourEntity e=entityList.get(i); if(i!=0){sqlBuilder.append(",");} sqlBuilder.append("(") .append(e.getPropertyValue1()) .append(",") .append(e.getPropertyValue2()) ... .append(")"); } return sqlBuilder.toString(); } } ``` 上述两种方案都可以满足动态设置表名的需求,在具体项目中可根据实际情况选择合适的方式[^1]。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值