客户反馈说致远oa协同在执行打开底表查询时报错:
操作异常!for Input string:
“-1.68557142844863E+16”
客户说这种报错有很多记录,报错中的科学计数法的字符串都不太一样。
数据库为DM8单机环境,应用服务是致远OA协同系统,达梦中的数据是从sqlserver中使用DTS迁移过来的,迁移配置也是使用的最基础的默认配置,没有做特殊配置(比如类型映射、表名映射等)。
客户第一反应是DTS迁移工具的问题,他觉得是从sqlserver迁移到DM后表中的数据变了,原来应该是整型的数据在迁移过程中被转换为科学计数法的字符串,然后导致应用服务在查询到这条数据时,应用服务的内部逻辑再将此字符串数据转换为整型时报错。
但是这种推断仔细思考一下后不太可能,因为从应用日志中看到的报错信息如下:
可以看到这个报错最直接的原因是java代码中在将用科学计数法表示的字符串转为Long类型时抛出了格式异常。既然是字符串类型,那DM中对应的表中肯定有字符串类型(VARCHAR、CHAR、TEXT等)字段中存储了科学计数法的字符串数据,然后迁移源端数据库SQLSERVER中源表中对应字段是数字类型(比如INT、NUMERIC、DECIMAL等),但是据我所知DTS在迁移表结构时进行字段类型映射不会做这种映射,但是问题没有排查出来之前先保留这种想法。
在从DM数据库表中查数据的同时客户也申请了致远的支持服务,等他们远程支持。
在等待过程中,我想了一下这个导致报错的科学计数法的字符串数据是哪里来的?
首先按照这个思路,我们需要找到有问题的数据,客户说科学计数法表示的字符串来自是formmain_6664这张表,然后我根据他提供的查询字段信息在DM管理工具中查询出来,并没有发现有这种字符串,接连查了好几条会导致地表查询报错的相关数据记录,也没有发现。既然这张表中没有,会不会其他表的数据?因为考虑到底表查询业务操作可能会对应多条SQL查询,那涉及到表也可能是多个,按照这个想法再去找了几个可能的相关表,但是也都没有发现问题数据,感觉这样找像大海捞针,现在只能等待应用服务的研发人员来分析问题数据的确切来源了。
再看下驱动是否一致,是否使用了和数据库版本一致的DMjdbc驱动,客户将OA应用所在服务器上的驱动文件看了一下文件大小(具体到字节数),对比下来也是一样的。
下午致远的支持工程师开始了远程协助,他们对业务系统代码非常熟悉,根据报错的业务层日志,很快定位到数据的来源,是从一个连表查询中查出来的,对应的字段其实是NUMERIC(19,0)类型,其中的数据也是正常的整型数据,并没有科学计数法的字符串存在,这种和我们上面推测的第二种情况吻合了,那就去定位应用逻辑或者驱动问题。
致远的工程师说这个报错的java代码逻辑是将一个object对象通过String.valueOf的方法转为String字符串,然后又用Long.ParseLong的方法转为Long类型时报错的,也就是说String.valueOf(object对象)计算的结果是一个科学计数法的字符串。object对象是通过jdbc的ResultSet.getObject(1)取到的jdbc对象,实际内部存储的是一个NUMERIC(19,0)的数字类型数据,大概的代码逻辑如下:
Object id_object = rs.getObject(1);
Long.parseLong(String.valueOf(id_object));
然后我按照这个逻辑使用最简单的demo进行了模拟,使用的jdbc驱动也是和此环境一样的版本,并没有模拟出来,这个就很奇怪了,难道他们用的驱动不对?但是上午查过OA服务用的驱动是一样的。
实在没有思路后,向公司大佬求助,说明了情况后,他说这种大概率和驱动有关系,可以从v$session系统视图中有个CLNT_VER字段会显示应用所使用的驱动版本。
经过查询发现OA系统建立的连接用的驱动版本确实是一个老版本驱动,那为什么上午看到的是新驱动呢?
这时候向客户确认了下,他到OA机器上找到了另一个位置的DMJdbcDriver文件,不是上午展示给我看的那个。然后我用java -jar DMJdbcDriver.jar的方式确认这个是老版本的驱动文件,和v$sessions中的CLNT_VER是相同的版本信息。我让他把这个文件传给我,然后用我本地的测试demo跑了一下,复现了此问题,String.valueOf(id_object)得到的结果确实是科学计数法格式的字符串,并且经过多次尝试只有后两位为00的数字才会被转为科学计数法的字符串。
到这儿基本确定问题了,OA用了一个老版本的驱动,从java -jar输出版本信息中看到是2019年的版本,这个版本存在这样的bug:通过String.valueOf(id_object)对末尾两位为00的整数数字会被转为科学计数法的字符串的问题。再和客户继续沟通后,发现上午查过的OA服务用的驱动文件是OA系统本身的,那个确实是新的,但是导致问题DMjdbc驱动文件是后面找到的老版本的驱动文件,它是给东方通中间件用的,所以遗漏了这个地方导致问题定位更曲折了一些,不过对应用的架构也更深入了一些。
此版本的驱动是6年多之前的了,从内部的bug列表中查看和这个有关的问题说明,找了一个21年的jdbc驱动测试已经没有这个问题了,说明已经早就被修复了。
这个问题再简化一下相当于是对NUMBERIC类型的后两位为00的数字进行getString方法获取时,获取到的结果是一个科学计数法的字符串。由于没有对这个问题直接的说明,但是看到一个已解决问题提到DECIMAL类型用getString获取时有类似的的问题,个人推断应该是使用了类似于BigDecimal类型的中间类型,在对数据库中查询出的NUMERIC类型数据包装后转换为String时,对某些数据(比如没有小数位的数字的后两位为00)进行判断为需要做科学计数表示。
在这次问题排查中,其实并没有很隐蔽的技术细节问题,反而是沟通和思考方向问题更多一些,总结下来有以下几点体会:
文章
阅读量
获赞
