达梦数据库与程序兼容性验证
以下是***应用中出现的两个数据库不一致的地方。
- 不支持utf8mb4编码
某些列需要支持录入emoj表情,所以需要编码为utf8mb4,但是达梦数据库不支持该编码。
解决方案:可在建表时将该列的数据类型,指定为Text,需要正确统计数据库中所有需要指定为Text类型的列。
注意:text类型的字段,在select时,需要进行to_char()函数转换,否则显示错误。如select id,content from table,应写为select id, to_char(content) content from table.
- 大小写敏感问题
为了避免sql语句中的所有别名都增加双引号,数据库迁移时指定了大小写不敏感,这样会造成sql语句的返回结果集的列明全部都是大写,程序中存在大量返回类型为List类型的接口,Map的key区分大小写,会造成本来数据库中存在的数据值,返回结果却为空。
解决方案:自定义HashMap子类,重写get、containKey等方法。
需要分情况替换mapper、service、controller以及其他类中的HashMap,主要依据mapper的返回值进行其他相关代码的修改。
先批量替换xml文件中的resultType=“java.util.HashMap”为resultType=“自定义map类全路径”;
批量替换mapper中的返回值 List 为List<自定义map>,批量替换import java.util.HashMap为import 自定义Map,若原代码确实需要引入HashMap,再重新引入;
批量替换service中的返回值为 List 为List<自定义map>;
批量替换controller中的返回值。
另外,数据库字段全部大写后,需要检查返回前端的数据格式是否发生变化。例如,有的直接将map转换成json后直接返回前端了。
解决方案:需要对map的数据进行转换或返回List数据格式替代List
需要修改的接口有:
/getWishList.do
/getContactUserByKeys.do
/getForumOperList.do
/getForumComment.do
/contactDeptsModified.do(作废)
- base64加密/解密函数
不能用mysql的from_base64()和to_base64()函数。
解决方案:采用系统包UTL_I18N、UTL_ENCODE,示例如下:
对“lily”加密如下:
UTL_I18N.RAW_TO_CHAR(UTL_ENCODE.BASE64_ENCODE(UTL_I18N.STRING_TO_RAW(‘lily’,‘UTF8’)))或
UTL_I18N.RAW_TO_CHAR(UTL_ENCODE.BASE64_ENCODE(UTL_I18N.STRING_TO_RAW(‘lily’)))
加密结果:bGlseQ==
对lily加密后的字符串进行解码:
select UTL_I18N.RAW_TO_CHAR(UTL_ENCODE.BASE64_DECODE(UTL_I18N.STRING_TO_RAW(‘bGlseQ==’)))
- Sql语句前是否需要增加模式名
解决方案:为避免每个sql语句访问时不添加模式名,需要:
数据库用户名=模式名。
-
Where子句中不支持case when
Where子句中的case when语句,需要修改,用and or方案。 -
case when 。。。 else 。。。 end
case when 。。。 else 。。。 end 语句中包含函数运算时,是对整个结果集进行函数运算,要实现对空数据、非空数据进行不同的处理时可能会报错,如:再对publicTo进行函数运算时,原则上应该是分两种情况,(1)publicTo为空时;(2)publicTo不为空时;
select publicTo, case when publicTo = ‘’ or publicTo IS NULL then ‘’ else UTL_ENCODE.BASE64_DECODE(UTL_I18N.STRING_TO_RAW(publicTo)) end publicTo1
from forum_comment where releaseId = 4777;
select distinct publicTo from forum_comment where releaseId = 4777;
下面这条数据publicTo数据不为空,才不报错,因为所有的结果集中publicTo都不为空:
select publicTo, case when publicTo = '' or publicTo IS NULL then '' else UTL_ENCODE.BASE64_DECODE(UTL_I18N.STRING_TO_RAW(publicTo)) end publicTo1
from forum_comment where ID =3928;
解决方案:
如果是insert语句,可以增加条件判断,如:
INSERT INTO table(publicTo)
VALUES
<choose>
<when test="forumComment.publicTo = null or forumComment.publicTo = ''">
''
</when>
<otherwise>
UTL_I18N.RAW_TO_CHAR(UTL_ENCODE.BASE64_ENCODE(UTL_I18N.STRING_TO_RAW(#{forumComment.publicTo})))
</otherwise>
</choose>
如果是select语句,用000000000不可能出现的字符串替代转换,再将结果’MDAwMDAwMDAw’替换为空串。如:
replace(UTL_I18N.RAW_TO_CHAR(UTL_ENCODE.BASE64_ENCODE(UTL_I18N.STRING_TO_RAW(case when publicTo == ‘’ OR publicTo is null then ‘000000000’ else publicTo end))),‘MDAwMDAwMDAw’,‘’)
-
不支持Insert into on duplicate key update
用merge into语句替换,但sql较长,并且using中的子表中每一列都要起别名。 -
不支持group_concat()函数
group_concat()函数,需替换为wm_concat或者listagg() within group(order by )语句,wm_concat()仅是将多个结果连接为一个字符串,如果需要排序或分隔符,就需要替代为 listagg within group函数。如需要将通讯地址以“|,”分隔的话,就需要替换为
(select listagg(address,‘|,’) WITHIN GROUP (order by shOrder asc) from contact_dept_addr where deptid = d.addrDeptId )
-
日期计算INTERVAL
日期函数date_sub(now(),INTERVAL 7 DAY) 需替换为date_sub(now(),INTERVAL ‘7’ DAY) -
不支持insert ignore into
insert ignore into 替换为 merge into
修改状态:暂未替换,比较繁杂,暂时去掉了ignore
- 不支持replace into
replace into 替换为 merge into
修改状态:暂未替换,比较繁杂,需要修改的地方也较多
-
tinyint类型数据返回不一致
tinyint类型数据返回不一致,columnValue=“1”,mysql返回true,达梦返回1。 -
不支持count distinct后面跟多列
count distinct 后面不能跟多列,只能一列,即 select count(distinct userId, userName) from contact_user报错
解决方案:select count(*) from (select distinct userId,userName from …)) a
- md5()函数返回不一致
md5()函数加密后的值与mysql加密后的值不同,前者加密后是十六进制数。
解决方案:to_char(md5(‘123’))
-
建表语句是否要去带模式名?模式名、表名、列名是否需要带双引号?是否需要带storage参数?
回复:不需要。 -
批量insert时存在自增序列的字段
如insert into user_info_list_history select * from user_info_list,其中p_id字段是自增序列,需要进行两项修改:
一是insert前需要设置目标表的自增序列字段允许插入值,而不是系统处理,这个修改比较简单;
二是要显示指明要插入目标表的各个字段,即:
set IDENTITY_INSERT user_info_list_history on;
insert into USER_INFO_LIST_HISTORY(USERACCOUNT, USERNAME, USERID, DEPTID, DEPTNAME, OAPASS, YWQX, P_ID, MAINDEPTID, FACECHECKFLAG, IFASKITSYSFORLEAVE, PY, LEAVELAUNCHSYSFLAG, USERORDER, OPERTIME)
select * from user_info_list ;
set IDENTITY_INSERT user_info_list_history off;
这一项比较麻烦,需要做很多个性化处理,每个表的字段都不同。
- 使用mybatis批量insert一个List报错
对于如下形式的批量数据库插入操作:
insert into table(column1,column2,…columnN)
List的size不超过8000时,就会报错:nested exception is dm.jdbc.driver.DMException: 第95258 行附近出现错误:
超过最大参数个数(32767)。
回复:目前无法解决,只能将list拆成多个,分次insert。
- 数据库性能较差
批量插入上万条数据,性能较差,如:
insert into approve_record select * from approve_record_history_2018
同样插入339,132条记录,达梦数据库使用了1分34秒,mysql数据库用了30.125秒,相差悬殊。