oracle+mybatis 使用动态Sql在要insert的字段不确定的情况下实现批量insert

本文探讨了在数据库表字段不确定的情况下,如何实现MyBatis中的批量插入操作。通过实例展示了如何构建动态SQL,利用Map和foreach循环来灵活处理未知字段数量的情况,并确保插入字段与值的一一对应。

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

最近做项目遇到一个挺操蛋的问题,由于业务的关系,DB的数据表无法确定,在使用过程中字段可能会增加,这样在insert时给我造成了很大的困扰。

先来看一下最终我是怎么实现的:

<insert id="batchInsertLine" parameterType="HashMap"> 

          <![CDATA[
	     INSERT INTO tg_fcst_lines(${lineColumn})
	        select result.*,sq_fcst_lines.nextval from(
	     ]]>
		  <foreach collection="lineList" item="item" index="index" separator="union all" > 
			  (select		  
			    <foreach collection="item"  index="key" item="_value" separator=",">
			          #{_value}
			    </foreach>	 
			  from dual)
		  </foreach>
		  <![CDATA[) result]]> 		 
	</insert> 

由于数据表不确定,所以我无法确定我要insert的字段,由于是批量insert,确定value值也挺费劲。

我传给mybatis的参数是一个map:

	Map insertMap = new HashMap();
	insertMap.put("lineColumn",lineColumn);		    	
	insertMap.put("lineList", lineList);
lineColumn是一个字符串,lineList是一个list:

List<Map> lineList = new ArrayList();
lineList里存放的是map,map的键对应数据表的字段,值是你要insert的值,这样就可以通过foreach取出list的值作为insert语句的value,但由于map是无序的,存放的顺序和

遍历时取值的顺序不一定一致,所以为了确保insert字段和值可以一一对应,可以通过遍历一次map来取出key拼接一个字符串作为insert的字段

String lineColumn = "";     //拼接的SQL,作为insert语句的一部分
Map<String,String> lineMap = lineList.get(0);
for (String key : lineMap.keySet()) {
	    lineColumn +=key+",";
}
lineColumn +="LINE_ID";


这里的line)id是一个自增的字段,在语句中直接写序列会报错,所以先遍历list将取出的值作为result,在取出result的所有值,连同序列一起作为insert的值。

在取值的时候使用两个foreace嵌套来实现,外层的foreach遍历list,里层的foreach遍历map,




版权声明:本文为博主原创文章,未经博主允许不得转载。

转载于:https://www.cnblogs.com/dingxiaoyue/p/4931720.html

<think>首先,用户的问题是:“我想查找在MyBatis使用Oracle数据库进行批量插入的操作方法或示例代码请问mybatisoracle批量插入insert示例”。我需要根据系统指令和提供的引用来回答。系统指令:-所有行内数学表达式用$...$格式(但这个问题不涉及数学,所以可能不需要)。-独立公式用$$...$$格式(同样,不适用)。-LaTeX语法正确(不适用,因为内容是代码示例)。-使用中文回答。-生成相关问题。-回答中引用的段落末尾自然地添加引用标识,例如[^1]。-回答结构清晰,帮助用户逐步解决问题,尽量保证回答真实可靠。用户可见层指令:-回答结构清晰,帮助用户逐步解决问题。参考的引用:-引用[1]:Mybatis批量插入数据(Oracle与MySQL),给出了Oracle和MySQL的示例代码。-引用[2]:mybatisoracle批量update和insert,给出了MySQL批量新增的示例。-引用[3]:oracle+mybatis批量插入的两种常规写法,给出了多表插入和单表插入的示例。用户的问题具体是关于MyBatisOracle批量插入示例。所以,我应该基于引用提供相关信息。从引用中提取关键点:-引用[1]:Oracle批量插入使用`<foreach>`标签,不需要添加VALUES,使用`unionall`。-示例代码:```xml<insertid="inser"parameterType="com.my.code.User">insertintotable_name(name,pwd,age)<foreachcollection="list"item="item"index="index"separator="unionall">(select#{item.name},#{item.pwd},#{item.age}fromdual)</foreach></insert>```-引用[3]:提供了两种写法:-多表插入:```xml<insertid="batchSave"parameterType="com.xuxd.bean.User">insertall<foreachcollection="list"item="user"separator=""open=""close=""index="index">intot_user(user_id,user_name)VALUES(#{user.userId},#{user.userName})</foreach>select1fromdual</insert>```-单表插入:```xml<insertid="batchSave"parameterType="com.xuxd.bean.User">insertintot_user(user_id,user_name)selectu.id,u.namefrom(<foreachcollection="list"index="index"item="user"open=""close=""separator="unionall">select#{user.userId}asid,#{user.userName}asnamefromdual</foreach>)u</insert>```用户的问题是专门关于Oracle批量插入,所以引用[1]和引用[3]最相关。引用[2]是关于MySQL的,可能不直接相关。回答结构:-我应该逐步解释如何在MyBatis使用Oracle进行批量插入。-提供示例代码。-引用来源,添加引用标识。-最后生成相关问题。结构清晰的回答:1.解释批量插入在Oracle中的常见方法。2.提供示例代码。3.解释代码的关键部分。4.添加注意事项。5.生成相关问题。使用中文回答。生成相关问题:在回答末尾添加相关问题,如示例所示。引用标识:在引用的段落末尾添加[^1],[^2],[^3]。但需要确保自然添加。现在,构建回答:-开头:直接回应用户的问题。-主体:提供示例代码和解释。-结尾:生成相关问题。示例代码:-使用引用[1]和引用[3]的代码。-引用[1]的代码更简洁,引用[3]提供了两种方式。优化回答:-先介绍Oracle批量插入的常见方法。-然后给出一个或多个示例。-解释为什么需要这样写(Oracle不支持VALUES多个值)。-添加注意事项。最终回答大纲:1.介绍:在MyBatis中,Oracle数据库批量插入通常使用`<foreach>`标签结合`unionall`或`insertall`语法。2.示例1:基于引用[1]的写法。3.示例2:基于引用[3]的两种写法。4.注意事项:如性能、长度限制等。5.引用标识。6.相关问题。确保真实可靠:基于提供的引用。</think>### MyBatisOracle 批量插入操作方法及示例代码 在 MyBatis使用 Oracle 数据库进行批量插入时,Oracle 不支持标准的 `VALUES` 多值语法(如 MySQL)。因此,常见的解决方案是结合 `<foreach>` 标签和 Oracle 特有的语法(如 `UNION ALL` 或 `INSERT ALL`)来实现高效批量插入。以下我将逐步解释操作方法并提供完整示例代码。所有内容基于可靠的技术文档和实际应用案例[^1][^3]。 #### 步骤 1:理解核心方法 Oracle 批量插入的两种主流写法: - **方法 1(单表插入)**:使用 `SELECT ... FROM DUAL` 结合 `UNION ALL`,将多个值作为子查询插入。 优点:语法简单,适用于中小批量数据;缺点:有长度限制(超过 1000 条可能报错)。 - **方法 2(多表插入)**:使用 `INSERT ALL` 语法,为每条记录单独指定插入目标。 优点:避免子查询嵌套,性能较好;缺点:语法稍复杂,需以 `SELECT 1 FROM DUAL` 结尾。 #### 步骤 2:示例代码 以下代码基于 MyBatis 的 XML 映射文件,使用 `parameterType` 指定集合类型(如 `java.util.List`)。请替换 `table_name` 和字段名以适应您的表结构。 ##### 示例 1:单表插入写法(推荐通用场景) ```xml <insert id="batchInsert" parameterType="java.util.List"> INSERT INTO table_name (user_id, user_name, age) SELECT u.id, u.name, u.age FROM ( <foreach collection="list" item="item" index="index" separator=" UNION ALL " open=" " close=" "> SELECT #{item.userId} AS id, #{item.userName} AS name, #{item.age} AS age FROM dual </foreach> ) u </insert> ``` - **关键点**: - `<foreach>` 标签遍历集合(`collection="list"`),生成多条 `SELECT` 语句。 - `separator=" UNION ALL "` 确保子查询合并为一个结果集。 - 外层 `INSERT INTO ... SELECT` 将子查询结果插入目标表。 - **适用场景**:数据量较小(建议 ≤1000 条),代码简洁易维护[^3]。 ##### 示例 2:多表插入写法(高性能场景) ```xml <insert id="batchInsert" parameterType="java.util.List"> INSERT ALL <foreach collection="list" item="item" index="index" separator=" " open=" " close=" "> INTO table_name (user_id, user_name, age) VALUES (#{item.userId}, #{item.userName}, #{item.age}) </foreach> SELECT 1 FROM dual </insert> ``` - **关键点**: - `INSERT ALL` 允许多个 `INTO` 子句,每个对应一条记录。 - `<foreach>` 动态生成 `INTO ... VALUES` 片段。 - 必须以 `SELECT 1 FROM dual` 结尾,这是 Oracle 的语法要求。 - **适用场景**:大数据量插入(性能更优),减少 SQL 解析开销[^1][^3]。 #### 步骤 3:注意事项 1. **长度限制**:OracleSQL 语句长度有限制(通常约 4000 字符)。如果批量数据过大,拆分批次执行(例如每批 500 条)以避免错误[^1]。 2. **性能优化**: - 在事务中执行批量插入,减少提交次数。 - 使用 `@Options(useGeneratedKeys=false)` 关闭主键返回(Oracle 批量插入不支持自动生成键)。 3. **错误处理**:如果报错(如 ORA-01745),检查字段名是否包含 Oracle 保留字或用反引号转义。 4. **参数类型**:确保 `parameterType` 正确指向集合类(如 `java.util.List`),且 `item` 属性名与实体类字段匹配。 #### 引用说明 以上方法参考了 MyBatis 社区的最佳实践,Oracle批量插入需依赖其特定语法而非标准 SQL[^1][^3]。 ### 相关问题 1. 如何优化 MyBatis 批量插入的性能以避免 Oracle 长度限制? 2. MyBatis 批量插入时如何处理主键生成(如序列)? 3. 在 Oracle 中,MyBatis 批量更新(update)的实现方法与插入有何不同? [^1]: Mybatis批量插入数据(Oracle与MySQL),详情见示例代码和注意事项。 [^3]: oracle+mybatis批量插入的两种常规写法,包括单表和多表插入示例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值