mybatis批量插入 insert foreach 操作传入map参数

本文介绍如何在MyBatis中使用Map参数进行批量数据插入,通过具体代码示例展示了如何配置XML映射文件及Java代码,实现将Map结构的数据高效地存入数据库。

很多情况下我们想直接在mybatis的insert操作中,传入一个map参数,然后将这个map保存到数据库中。网上查了好多,说的比较乱,试了好多最后还是自己神来之笔,竟然搞定。这里简单整理一下。

废话后面将,直接贴代码:

map接口

public interface Mapper{
  void insert(Map<String,Map<String,Integer>> params);
}


xml配置

<insert id="insert" keyProperty="id" useGeneratedKeys="true" parameterType="hashmap">
        INSERT INTO 表名 (c1,c2) VALUE
<!-- collection="keys"中的keys和最外层的map得key对应,不用管dao层的定义的那个参数名,且index=“key” 中key这个也是固定的,                          -->
        <foreach collection="keys" index="key" item="value" separator="," >
        <!--这个地方也是固定写法,key代码map的key,value代表map中该key对应的value-->
            (#{key},#{value}) 
        </foreach>
    </insert>

main方法中调用

SqlSession session = SessionFactoryUtil.openSeeion();
CommonMapper cm = session.getMapper(Mapper.class);          
Map<String,Integer> map = new HashMap<>();
map.put("key1",1);
map.put("key2",2);
map.put("key3",2);
Map<String,Map<String,Integer>> params = new HashMap<>();
params.put("keys",map);
mapper.insert(params);
session.commit();
session.close();

相信很多同学都遇到和我一样的问题,看到这里我想不需要解释太多你也已经大概清楚。简单啰嗦几句。

有时候为了方便,我们并不想写那么多java bean,这时候我们会考虑用map,map很方便,键保存一个值,值又保存了一个值,完事儿,前提是你的键保存的那个值不能重复。

简单举个栗子,比如我们要保存两个值,一个是人名(name),一个是年龄(age),熟悉java bean的同学,肯定会首先想到写一个如下的bean出来:

public class Person{
  private String name;
  private Integer age;
}

这样当我们保存一堆人的时候,可能就会new一个ArrayList,然后把这些人添加进去,再把这个list对象持久化到数据库。

List<Person> personList = new ArrayList();
personList.add(person1);
personList.add(person2);
...
insert(personList);

看起来挺好,没什麽毛病。


但是,但是,,如果一直这样为简单两个变量就写一个bean出来,,,将来再select操作的时候也要再包装一层。。

卧槽 我要吐了!!

直接放到map里面保存,多方便!!

Map personMap = new HashMap<>();
personMap.put("John",23);
personMap.put("Lee",34);
personMap.put("Julia",19);
insert(personMap);//?大家都想这样操作对嘛?这样的确很爽!但简单这样还不行,配置文件的foreach没法写

正确的做法是需要把我们真正想保存的map再包装再另一个map中

Map<String,Map<String,INteger>> param = new HashMap<>();
param.put("keys",personMap); //注意,这里的"keys",对应foreach中的collection
insert(param);  //这样把这个map的map传入到方法中才能进行插入

个人觉得为了两个变量就动辄使用一个java bean,虽然设计上比较合理,符合java面向对象思想,

由于读者反馈测试不成功,我用springboot+mybatis又进行了测试,并将代码上传,代码地址如下:

download.youkuaiyun.com/download/weter_drop/11990558
将代码下载下来,修改数据库连接为自己本地的,并建好对应的表,运行如下图所示 的测试类即可
在这里插入图片描述

### 实现方式 在使用 MyBatis 插入数据时,若传入参数为 `Map` 类型,并且其中的 Key 是数据库列名,Value 是对应的值,可以通过 `<foreach>` 标签对 Map 进行遍历来动态构建 SQL 语句。这种方式适用于每次插入的数据列不固定的情况。 #### Mapper XML 文件中的 SQL 定义 在定义 SQL 语句时,可以利用 `collection="map"` 和 `index="key"` 来分别表示 Map 中的键和值。通过 `<foreach>` 遍历 Map 的键作为列名,并将对应的值作为插入值[^2]。 ```xml <insert id="importExcel"> INSERT INTO ${table_name} <foreach item="value" collection="map" index="key" open="(" separator="," close=")"> ${key} </foreach> VALUES <foreach item="value" collection="map" index="key" open="(" separator="," close=")"> #{value} </foreach> </insert> ``` #### Java 接口定义 为了确保在 XML 中正确引用参数名称,需要使用 `@Param("map")` 注解明确绑定参数名称。此外,还可以传入表名作为另一个参数: ```java void importExcel(@Param("table_name") String tableName, @Param("map") Map<String, Object> dataMap); ``` #### 使用示例代码 在调用方法时,只需要构造一个包含列名与对应值的 `Map` 对象,并传入目标表名即可: ```java Map<String, Object> dataMap = new HashMap<>(); dataMap.put("user_id", 1); dataMap.put("user_name", "john_doe"); dataMap.put("email", "john.doe@example.com"); mapper.importExcel("users", dataMap); ``` #### 注意事项 - **安全性**:由于列名和表名是直接拼接的(使用 `${}`),需特别注意 SQL 注入问题。建议对传入的列名和表名进行白名单校验以增强安全性。 - **可读性与维护性**:这种动态构建 SQL 的方式提高了灵活性,但也可能降低代码的可读性和维护性。建议在关键业务逻辑中增加注释或文档说明。 - **兼容性**:如果涉及多个数据库类型(如 MySQL、PostgreSQL 等),可以结合 `<if test="">` 或其他 MyBatis 动态 SQL 元素实现条件判断,从而适配不同数据库的语法差异。 ### 相关问题 1. 如何在 MyBatis 中动态更新表中的特定字段? 2. MyBatis 中如何处理批量插入操作? 3. 在 MyBatis 中使用 Map 作为参数时,如何避免 SQL 注入风险? 4. MyBatis 是否支持根据不同的数据库类型自动调整 SQL 语句?
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

T-OPEN

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值