事件发生的背景同动弹同步,我接到了一个把我的项目从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 ]]>