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 ]]>
相關文章
相關標籤/搜索