以MySQL数据库开发的内容管理系统,需要兼容Oracle数据库遇到的问题以及解决方案。

一、问题背景描述

开发的系统默认MySQL数据库,现在需要适合Oracle数据库,初始化数据库SQL和代码中包含MySQL的执行SQL需要重新定义。

二、目前遇见的问题(18.6.19)

1、Oracle的表名和列名长度只支持30个字符以内。

2、MySQL中ifnull()函数和format()函数等等等不存在于Oracle数据库中。

3、存储过程语法不同。

4、分页查询语法无法写出通用的SQL。

三、问题分析以及解决方案。

1、Oracle的表名和列名长度只支持30个字符以内。

解决方案:简化长度过长的表名和列名,新建更新SQL。

# 调整表WCMMetaTableGovDocSelfAssessment的名称为WCMMetaTableGovDocSelfAs(兼容oracle中表名的长度限制)
alter table WCMMetaTableGovDocSelfAssessment rename WCMMetaTableGovDocSelfAs ;

# 调整表列表名WCMMetaTableGovDocSelfAssessmentID的名称为WCMMetaTableGovDocSelfAsID(兼容oracle中表名的长度限制)
ALTER TABLE WCMMetaTableGovDocSelfAs CHANGE WCMMetaTableGovDocSelfAssessmentID WCMMetaTableGovDocSelfAsID INT(11);

2、MySQL中ifnull()函数和format()函数等等等不存在于Oracle数据库中。

(1)问题分析:Oracle不支持ifnull函数和format的函数,但是在统计类业务逻辑中使用大量的拼接SQL,因此目前解决的方案有两个,一个是修改为通用的SQL,一个是获取数据库信息,根据判断执行不同的SQL。

统计类业务中拼接SQL数量过于庞大,如果根据数据库写成两个逻辑,一方面是工作量过大,另一方面不断的请求数据库,会对服务器造成不必要的压力,并发越大,产生的性能影响就是之前的两倍。

最后,MySQL和Oracle都支持SQL99标准。

(2)解决方案:

目前在统计业务类中,主要涉及到的是ifnull和foamat这两个韩函数。因此,优先选择修改拼接SQL,使用共用的SQL。

(3)解决过程:

ifnull(EXPR1,EXPR2)的用法是EXPR1不为空返回EXPR1,否则返回EXPR2,一般返回的是数字或者字符串。

nullif(EXPR1,EXPR2)的用法是EXPR1等于EXPR2时,返回空,否则返回EXPR1

在Oracle中,不支持ifnull,只支持nullif,MySQL中的ifnull等价于decode(),但是目前必须是要写一个通用的SQL,如果是能通用的函数就更好。

仔细的查询过Oracle的相关函数资料以后,找到了一个尽可能类似的函数COALESCE(EXPR1,EXPR2,EXPR3...EXPRn),然而测试过后,发现这个函数只支持字符串类型的数据。

最后只能选择使用case when else end  这个使用起来略繁杂的语法。

(4)代码案例

不兼容代码:

"FORMAT(IFNULL((COUNT( CASE WHEN STATUSID IN (19) THEN 0 END )/" +
"COUNT(WORKORDERID))*100,0),0) as finalSolvedRate," +

兼容代码:

"ROUND(CASE WHEN((COUNT( CASE WHEN STATUSID IN (19) THEN 0 END )/" +
"COUNT(WORKORDERID))*100) IS NOT NULL THEN ((COUNT( CASE WHEN STATUSID IN (19) THEN 0 END )/" +
"COUNT(WORKORDERID))*100) ELSE 0 END,0) as finalSolvedRate," +

(5)format和round。

在MySQL中,format的用法是格式化数据,可支持数字、日期格式。round只支持数字格式。

3、存储过程语法不同

(1)问题分析:关于存储过程的语法不同,这个就没有办法兼容了,一般存储过程都是存在于初始化SQL里面,不会出现在代码中的拼接SQL。

(2)解决方案:新写一套Oracle版本初始化SQL。

4、分页查询语法无法写出通用的SQL

(1)问题分析:MySQL中可以使用limit来选择想要获取的数据,但是在Oracle中就只能使用伪列,伪列只能从一开始,必须要嵌套起来子查询。

(2)解决方案:因为代码中含有这个分页获取数据的拼接SQL,就必须写两个逻辑。

(3)解决过程:连接数据库,获取数据库类型,然后根据类型选择拼接的SQL。

if (itemCount > 0) {
    DBManager dbMgr = DBManager.getDBManager();
    if (dbMgr != null) {
        try (Connection oConn = dbMgr.getConnection()
        ) {
            DatabaseMetaData data = oConn.getMetaData();
            String dataName = data.getDatabaseProductName();
            //如果总记录数大于0 分页 支持mysqloracle
            if (dataName.equalsIgnoreCase("MySql")) {
                sql = sql + " limit " + pageBean.getStartIndex() + "," + pageBean.getPageSize();

            } else if (dataName.equalsIgnoreCase("Oracle")) {
                sql = "SELECT * FROM (SELECT tabs.*, ROWNUM AS rowno FROM ( " + sql +
                        " ) tabs  WHERE ROWNUM <= " + pageBean.getEndIndex() +") table_alias  WHERE table_alias.rowno >= "+pageBean.getStartIndex() ;
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

四、总结

数据库类型各种各样,开始的时候写的SQL尽量符合SQL标准的。

代码中尽量少的使用拼接SQL。

尽可能熟悉各大主流数据库。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值