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

事件发生的背景同动弹同步,我接到了一个把我的项目从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中的转移字符如下:    

              &lt;                 >        大于号
             &gt;                <         小于号
            &amp;                 &             和
           &apos;                 '         单引号
           &quot;                "          双引号

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

mapper文件示例代码

<![CDATA[ where rowno <=60 and rowno >=40 ]]>     

 

转载于:https://my.oschina.net/ytliyang/blog/794747

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值