mybatis-foreach循环insert

MyBatis批量插入示例
本文介绍如何使用MyBatis框架通过传递Map类型的参数来实现批量数据插入操作。具体展示了如何构造Map数据并配置XML文件中的SQL语句,利用<foreach>标签进行循环插入。

首先传入一个Map类型数据

Map<String, Object> map = new HashMap<String, Object>();
        map.put("questionid", result1);
        map.put("labelid", list_labelid);

然后在xml中这样写SQL

<insert id="insert" parameterType="map" >

      insert into label_resources (questionid, labelid)
      values
          <foreach collection="labelid" item="item" index="index" separator=",">
              (#{questionid,jdbcType=BIGINT},#{item})
          </foreach>

</insert>

因为我这里只循环了labelid所以直接就是#{item},记住加上separator=","这句标签,不然循环的语法就错了。

<think>我们正在讨论MyBatisforeach标签的解析原理。根据引用[2]和引用[3],我们可以知道foreach标签在MyBatis中用于动态SQL,特别是在批量操作中。现在,我们需要深入解析其工作原理。 解析原理: 1. **解析阶段**:MyBatis在启动时会加载并解析所有的XML映射文件,将每个SQL语句(包括动态SQL)解析成一个个的SqlNode对象。对于foreach标签,会被解析成ForEachSqlNode对象。 2. **动态SQL处理流程**:当执行带有foreach标签的SQL语句时,MyBatis会进入动态SQL处理流程。ForEachSqlNode会根据传入的集合参数(Iterable或Map等)进行循环处理。 3. **循环处理**:在每次循环中,ForEachSqlNode会将当前循环项添加到上下文中(通过OGNL表达式可以访问),然后解析并拼接foreach标签内部的SQL片段。 4. **拼接规则**: - 使用`separator`属性指定的字符串作为每次循环之间的分隔符(如逗号)。 - 循环中可以使用`item`属性指定的变量名访问当前项,如果指定了`index`属性,则可以用它来访问当前循环的索引。 5. **最终SQL生成**:循环结束后,所有循环生成的SQL片段会拼接成一个完整的字符串,然后替换掉原SQL中foreach标签的位置。 举例说明: 引用[3]中的批量插入示例: ```xml <insert id="saveList"> insert into table (id, column) values <foreach collection="list" item="item" index="index" separator=","> (#{item.id}, #{item.column}) </foreach> </insert> ``` 假设传入一个包含三个元素的list,则生成的SQL为: ```sql insert into table (id, column) values (?, ?), (?, ?), (?, ?) ``` 注意点: - 集合类型:`collection`属性指定要遍历的集合,可以是List、Set、Map、数组等。 - 参数绑定:在循环体内,通过`#{}`表达式引用当前循环项(item)的属性,这些表达式会被预编译为PreparedStatement的参数占位符(?),然后逐个赋值。 底层机制: MyBatis使用OGNL(Object-Graph Navigation Language)表达式来访问集合中的元素和对象的属性。在循环过程中,每次迭代都会创建一个新的上下文环境,将当前项和索引(如果有)放入上下文中,然后解析循环体内的SQL片段。 性能考虑: 使用foreach标签进行批量操作(如插入)比在Java中循环调用单条插入性能更高,因为减少了数据库交互次数(一次连接执行一条包含多条数据的SQL)[^3]。 特殊情况处理: - 空集合:MyBatis对空集合有保护机制,如果传入的集合为空,则foreach标签内的内容不会生成,避免SQL语法错误。 - 嵌套循环foreach标签可以嵌套(如引用[4]中的示例,但注意引用[4]中使用了foreach嵌套if标签,这是动态SQL的复杂用法),但需要确保嵌套循环的变量名不冲突。 引用[4]中的例子展示了foreach嵌套if标签,用来动态生成UNION查询: ```xml <select id="getYsxmcodeByYszbh" resultType="java.util.Map"> <foreach collection="qyName" index="index" item="qy"> <if test="index != 0"> union </if> select ysxmcode from ${qy}_yxsxk.tpc_ysxkz where yszbh=#{yszh,jdbcType=VARCHAR} </foreach> </select> ``` 在这个例子中,foreach遍历集合`qyName`(一个公司名称列表),对于第一个元素(index=0)不添加UNION,后续每个元素前添加UNION,从而拼接成一个UNION查询。 总结: MyBatis中的foreach标签通过动态解析和拼接SQL来实现循环操作,其核心是ForEachSqlNode类在运行时对集合进行迭代并生成相应的SQL片段。这种方式在批量操作中可以显著提高性能。 相关问题: 1. 在MyBatis中使用foreach批量插入时,当集合为空会导致SQL语法错误吗? 2. MyBatisforeach标签支持的集合类型有哪些? 3. 如何避免foreach批量操作导致SQL语句过长(超过数据库限制)? 4. 在foreach循环体内如何访问外层参数? 5. 动态SQL解析过程中,MyBatis如何处理特殊字符(如转义)? </think>### MyBatis XML中foreach循环的解析原理 MyBatis的`foreach`标签在XML映射文件中实现动态SQL,其解析过程可分为三个阶段: #### 1. **SQL解析阶段** - MyBatis启动时解析XML文件,将`foreach`标签转换为`ForEachSqlNode`对象 - 识别关键属性: - `collection`:待遍历的集合表达式(如`list`,`array`,`map`)[^2] - `item`:当前元素的引用变量名 - `index`:循环索引变量名(可选) - `separator`:元素间的分隔符(如`,`) - 示例: ```xml <foreach collection="users" item="user" separator=","> (#{user.id}, #{user.name}) </foreach> ``` #### 2. **运行时处理阶段** 当执行SQL时,动态引擎按以下步骤处理: 1. **解析集合表达式**: 通过OGNL表达式解析`collection`值(如`list`对应传入的List对象) 2. **迭代生成SQL片段**: ```mermaid graph TD A[开始循环] --> B{集合未结束?} B ----> C[绑定当前元素到item变量] C --> D[解析嵌套内容为SQL片段] D --> E[添加separator分隔符] E --> B B ----> F[拼接最终SQL] ``` 3. **参数绑定**: 将`#{item.property}`转换为预处理参数占位符`?`并缓存参数值 #### 3. **SQL生成阶段 生成完整的SQL语句: ```sql -- 原始SQL INSERT INTO users VALUES -- 解析后(假设3个元素) (#?, #?), (#?, #?), (#?, #?) ``` - **特殊处理**: - 空集合跳过整个`foreach`块 - 首尾自动去除多余分隔符 - 嵌套`if`标签支持条件过滤(如引用[4]的`union`控制)[^4] #### 性能优化原理 1. **单次数据库交互**: 相比Java循环多次执行SQL(引用[3]),`foreach`生成单条批量SQL,减少网络开销[^1] 2. **预编译优势**: 虽生成多参数占位符,但数据库只需解析一次SQL模板 3. **事务统一**: 所有操作在同一个事务中完成,保证原子性 > **典型应用场景**: > - 批量插入(如引用[3]的`saveList`)[^3] > - 动态条件查询(`WHERE id IN <foreach...>`) > - 跨表联合查询(如引用[4]的分表UNION操作)[^4]
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值