oracle和达梦数据库的区别杂谈

这几天正在做数据库国产化的相关工作,之前的一个项目数据库用的是oracle的,现在要换成达梦的。所以我就把遇到的,需要修改的列出来,本篇文章持续更新中。

目录

1 达梦数据库中会出现多余的0占位

2 order by 排序的时候会把null空值排前面

3 is null,is not null与空字符不兼容

4 达梦数据库查询语句严格区分字符串尾部空格问题

5 oracle有自动收集统计信息的定时任务,而达梦需要自己去弄个定时任务

6 oracle和达梦date数据类型区别


1 达梦数据库中会出现多余的0占位

无论是oracle还是达梦数据库,都有number类型,格式都为number(m,n)。两个数据库中有相同的表,由于业务需求,我不能将原表的相关表的表结构晒出,现将测试表的结构展示如下:

CREATE TABLE CESHI (

ID VARCHAR2(50) DEFAULT SYS_GUID() NOT NULL,

NAME VARCHAR2(50) NULL,

ADDRESS VARCHAR2(50) NULL,

COLUMN1 VARCHAR2(70) NULL,

TOTAL NUMBER(15,3) NULL,

CONSTRAINT CESHI_PK PRIMARY KEY (ID)

);

达梦数据库的数据如下:

oracle数据库如下:

java端用的是springboot加mybatis,代码如下:

package boke.hbc.dingshiqi.ceshi; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; @RequestMapping("/ceshi") @RestController public class CeshiController { @Autowired private CeshiService service; @RequestMapping(value = "/dmandorcl") public JSONObject dmandorcl() { List<Map> list1=service.dmandorcl(); for(Map map1:list1) { System.out.println(map1.toString()); } JSONObject resultjson=new JSONObject(); resultjson.put("code", 0); return resultjson; } }

service:

package boke.hbc.dingshiqi.ceshi; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.alibaba.fastjson.JSONObject; @Service public class CeshiService { @Autowired CeshiMapper mapper; public List<Map> dmandorcl() { // TODO Auto-generated method stub return mapper.dmandorcl(); } }

mapper

package boke.hbc.dingshiqi.ceshi; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; @Mapper public interface CeshiMapper { @Select("select * from ceshi") List<Map> dmandorcl(); }

在oracle数据库的情况下,控制台显示如下:

{TOTAL=777, ADDRESS=null, ID=22222, COLUMN1=null, NAME=null}
{TOTAL=444.745, ADDRESS=z, ID=2F172A78A876449F8B267927741774FB, COLUMN1=null, NAME=ssss}
{TOTAL=111, ADDRESS=ddd, ID=AB26EE87BFFF4ED7B4A666FBCAF357CC, COLUMN1=null, NAME=ssssf}

在dameng数据库环境下,控制台显示如下:

{TOTAL=22.000, ADDRESS=null, ID=22222, COLUMN1=null, NAME=null}
{TOTAL=344.000, ADDRESS=z, ID=2F172A78A876449F8B267927741774FB, COLUMN1=null, NAME=ssss}
{TOTAL=22.870, ADDRESS=ddd, ID=AB26EE87BFFF4ED7B4A666FBCAF357CC, COLUMN1=null, NAME=ssssf}

这种小数点后三个0的情况输入到前端页面显然是不合适的,所以我做了个拦截器,代码如下:

package com.bocomsoft.util; import java.math.BigDecimal; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.MappedJdbcTypes; import org.apache.ibatis.type.MappedTypes; @MappedJdbcTypes({JdbcType.NUMERIC,JdbcType.DECIMAL}) @MappedTypes(BigDecimal.class) public class BigDecimalTypeHandler extends BaseTypeHandler<String> { @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { // TODO Auto-generated method stub System.out.println("i="+i+"@parameter="+parameter+"@jdbcType="+jdbcType.toString()); ps.setString(i, parameter); } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { // TODO Auto-generated method stub //System.out.println("哈哈1="+columnName); BigDecimal val = rs.getBigDecimal(columnName); if(val!=null) { String val2=val.toPlainString(); if (val2.indexOf(".") > 0) { // 去掉多余的0 val2 = val2.replaceAll("0+?$", ""); // 如果最后一位是. 则去掉 val2 = val2.replaceAll("[.]$", ""); } return val2; }else { return ""; } } @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { // TODO Auto-generated method stub //System.out.println("哈哈2"); BigDecimal val = rs.getBigDecimal(columnIndex); if(val!=null) { String val2=val.toPlainString(); if (val2.indexOf(".") > 0) { // 去掉多余的0 val2 = val2.replaceAll("0+?$", ""); // 如果最后一位是. 则去掉 val2 = val2.replaceAll("[.]$", ""); } return val2; }else { return ""; } } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { // TODO Auto-generated method stub //System.out.println("哈哈3"); BigDecimal val = cs.getBigDecimal(columnIndex); if(val!=null) { String val2=val.toPlainString(); if (val2.indexOf(".") > 0) { // 去掉多余的0 val2 = val2.replaceAll("0+?$", ""); // 如果最后一位是. 则去掉 val2 = val2.replaceAll("[.]$", ""); } return val2; }else { return ""; } } }

这样输出的结果就不带有多余的0了

2 order by 排序的时候会把null空值排前面

在oracle中,select语句如果涉及到排序,默认的情况是把排序字段中为null的值排后,而达梦数据库正好相反,还是看那个ceshi表,两个数据库执行同样的sql语句:SELECT * FROM ceshi t ORDER BY t.ADDRESS,oracle的执行结果如下所示:

而达梦数据库则变成这个样子了:

如果要做数据库适配的话一定要注意。

3 is null,is not null与空字符不兼容

在oracle中,如果一个字段的值是空字符得话,他与null是等价的,我们可以用is null或is not null进行判断,但是达梦有可能是不一样,空字符和null不是等价的。主要与数据库设置有关,这个参数叫COMPATIBLE_MODE,具体参考链接如下所示:达梦数据库非空约束错误解决,明明插入空字符串,但还是触发非空约束_达梦数据库违反列非空约束-CSDN博客

4 达梦数据库查询语句严格区分字符串尾部空格问题

在oracle数据库中,是严格区分'a'和'a '的,但是在达梦数据库中是有可能不区分的,可数据库的BLANK_PAD_MODE参数,当BLANK_PAD_MODE=0时,除去group by 这种分组操作时严格区分外,其他比较、count等操作不严格区分'a'和'a ',认为这两个字符串是相等的。而且比较坑的是数据库实例已经建立的情况下,他是不能改的,除非重装数据库((╯‵□′)╯︵┴─┴ 掀桌),补救的措施是修改SPACE_COMPARE_MODE参数,然后重启服务器,右空格可以这么解决,左空格自求多福吧,我当时找的参考链接如下:

达梦数据库查询语句严格区分字符串尾部空格问题_达梦数据库空格填充模式-CSDN博客

5 oracle有自动收集统计信息的定时任务,而达梦需要自己去弄个定时任务

这个问题我当时是这么发现的,当时我们达梦上的测试库和正式库的数据量差不多,然后我就发现正式库查询特别慢,我就问达梦数据库的售后咋回事,他调了半天,说oracle默认的情况下有自动收集统计信息的定时任务,当高于一个阈值的时候,他会自动进行收集统计信息。达梦需要自己弄(后来我在网上看到说达梦也可以进行设定,但是我没时间,以后去验证一下吧),他就用sysdba用户加了个定时任务,里面执行的sql脚本为:CALL DBMS_STATS.GATHER_SCHEMA_STATS('大写的用户名',100,TRUE,'FOR ALL COLUMNS SIZE AUTO'),每两天执行一次,参考链接如下:

达梦数据库如何收集统计信息?_达梦收集统计信息-CSDN博客

6 oracle和达梦date数据类型区别

oracle和达梦都有date数据类型,但oracle是精确到秒,达梦只能精确到天,默认值都可以用sysdate,所以,如果达梦想要精确到秒,数据类型应该使用TIMESTAMP,在日期计算上,也是有区别的,总结如下:

在达梦数据库中,SYSDATE + 1表示‌当前系统时间往后推 1 天‌(即 24 小时)。

  • 运算单位‌:达梦日期运算以“天”为基本单位,整数1代表 1 天 。
  • 语法示例‌:SELECT SYSDATE + 1 FROM DUAL;返回明天的日期时间。
  • 其他精度‌:若需计算小时或分钟,需转换为天数,如加 5 小时写作SYSDATE + 5.0/24。‌‌