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

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

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

 

    一、mysql和oracle的分页方式不同,涉及到分页的地方要注意数据库

    二、oracle的自增加要写函数本身实现,并不能像MySql那样去直接用自增加属性mybatis

    三、mysql中的不少经常使用字段如 id,name,sort,description...在Oracle中被强制为关键字占用,因此你在mysql中导出的建表语句并不适用oracle

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

    五、日期字段的处理,这个我就很少说了函数

    六、空字符的处理,MYSQL的非空字段也有空的内容,ORACLE里定义了非空字段就不允许有空的内容。按MYSQL的NOT NULL来定义ORACLE表结构,导数据的时候会产生错误。所以导数据时要对空字符进行判断,若是为NULL或空字符,须要把它改为一个空格的字符串。测试

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

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

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 ]]>
相关文章
相关标签/搜索