您的位置:首页 > 数据库 > Oracle

Oracle数据库批量foreach涉及union all插入自增长主键实现方案

2016-11-26 00:00 204 查看
摘要: 在Oracle数据库中采用MyBatis框架进行数据的foreach批量插入时涉及了union all 出现的种种问题进行总结。也源于自己对Oracle的不熟悉。

事件发生的背景同动弹同步,我接到了一个把我的项目从mysql迁移到oracle数据库的噩耗。本来以为这事件麻烦的事儿,但是实际情况比我想的麻烦的多。

顺便总结一下我换库遇到的种种问题:

1、mysql和oracle的分页方式不一样,涉及到分页的地方要注意

2、oracle的自增长要写函数自己实现,并不能像MySql那样去直接用自增长属性

3、mysql中的很多常用字段如 id,name,sort,description...在Oracle中被强制为关键字占用,所以你在mysql中导出的建表语句并不适用

4、mysql和oracle中字段类型不通用,这也导致了你mysql中导出的建表语句并不适用

5、日期字段的处理,这个我就不多说了

6、空字符的处理,MYSQL的非空字段也有空的内容,ORACLE里定义了非空字段就不容许有空的内容。按MYSQL的NOT NULL来定义ORACLE表结构,导数据的时候会产生错误。因此导数据时要对空字符进行判断,如果为NULL或空字符,需要把它改成一个空格的字符串。

这些都是次要的,下面我们来切入主题:

第一步,实现oracle的自增长,首先你要有一个序列

CREATE SEQUENCE portal_sequence  --序列名
INCREMENT BY 1   -- 每次加几个
START WITH 250       -- 从1开始计数
NOMAXVALUE        -- 不设置最大值
NOCYCLE;               -- 一直累加,不循环  ;

定义好sequence后,你就可以用currVal,nextVal取得值。
CurrVal:返回 sequence的当前值
NextVal:增加sequence的值,然后返回 增加后sequence值

然后在进行插入操作时就可以:

insert into p_sys_rolemenu (rm_id,role_id, menu_id,creator, create_time,update_time,updator, is_deleted)

select  get_seq('portal_sequence.nextval') , 2,113,053023,sysdate,sysdate,053023,0 from dual

第二步,也是我们要处理的问题了:我在mybatis中涉及了批量的插入使用了foreach,然后我把当时在mysql底下的xml问题贴出来。

<insert id="insert" parameterType="com.aneop.sys.userfunc.entity.RoleMenu" >
insert into t_sys_rolemenu (role_id, menu_id,creator, create_time,update_time,updator, is_deleted)
<foreach collection="list" separator="UNION ALL" item="item">
select #{item.roleId},#{item.menuId},#{item.creator},NOW(),NOW(),#{item.creator},0
</foreach>
</insert>

然后这个肯定是不行的啊,没有rm_id的自增长主键。所以我就稍微修改了下:

理所应当的把portal_sequence.nextval加上去了,然后测试了一下,竟然成功了,然后我继续测了一下才发现,在list.size()<=1的时候是没问题的,一旦list里面有两条/两条以上的记录时就涉及到了union all,然后就又不成功了。

<insert id="insert" parameterType="com.ane56.sys.userfunc.entity.RoleMenu" >
insert into p_sys_rolemenu (rm_id,role_id, menu_id,creator, create_time,update_time,updator, is_deleted)
<foreach collection="list" separator="UNION ALL" item="item">
select  portal_sequence.nextval, #{item.roleId},#{item.menuId},#{item.creator},sysdate,sysdate,#{item.creator},0 from dual
</foreach>
</insert>

经过网上一翻查找,最后定义到了问题,要先创建函数才可以,创建函数get_seq()

create or replace function get_seq (p_in_sqname in varchar2) return number
is
l_res number ;
begin
execute immediate 'select '|| p_in_sqname|| '.nextval from dual' into l_res ;
return l_res ;
end ;

然后我把我xml里面的foreach修改为如下情况,在调用序列的时候通过我的get_seq()函数来调用:

<insert id="insert" parameterType="com.ane56.sys.userfunc.entity.RoleMenu" >
insert into p_sys_rolemenu (rm_id,role_id, menu_id,creator, create_time,update_time,updator, is_deleted)
<foreach collection="list" separator="UNION ALL" item="item">
select  get_seq('portal_sequence.nextval'), #{item.roleId},#{item.menuId},#{item.creator},sysdate,sysdate,#{item.creator},0 from dual
</foreach>
</insert>

问题完美解决,这个bug浪费时间超过两个,在此记录下。

附带贴上mybatis中的转移字符如下:

<>大于号
><小于号
&&
''单引号
""双引号
因为这个是xml格式的,所以不允许出现类似“>”这样的字符,但是都可以使用<![CDATA[ ]]>符号进行说明,将此类符号不进行解析
你的可以写成这个:

mapper文件示例代码

<![CDATA[ where rowno <=60 and rowno >=40 ]]>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息