mongoDB执行插入语句报错,后台的请求参数及异常信息,如下:
2020-05-20 11:15:04.037 INFO [http-nio-8080-exec-2] com.web.controller.BaseManageController - dataJson={"isCalculate":true,"name":"测试_01","defaultResult":0.1}
2020-05-20 11:15:04.062 DEBUG [http-nio-8080-exec-2] org.mongodb.driver.protocol.command - Execution of command with request id 195 failed to complete successfully in 16.18 ms on connection [connectionId{localValue:10, serverValue:108054}] to server 127.0.0.1:27017
com.mongodb.MongoSocketReadException: Prematurely reached end of stream
at com.mongodb.internal.connection.SocketStream.read(SocketStream.java:92)
项目所用mongodb和mongodb-java-driver版本信息如下:
mongodb的版本是:2.8.0-rc5
mongodb-java-driver版本是:3.8.2
从网上搜索 Prematurely reached end of stream 大部分说的是连接池满了什么的,重启或者修改配置之类的,但是按照搜索到的方案修改之后,仍然解决不了问题。
而且,这个问题,并不是每次都会出现,我直接在postman中,使用以前的调试和测试的数据,提交到接口,插入都是正常的,只有同过页面提交数据到这个接口,这个插入方法就报错,然后我就分析了页面提交的参数,并和我以前的调试和测试的数据进行对比,发现数据结构基本一致,但是只有一处不同:
页面提交的参数中, 是:"defaultResult":0.1
调试和测试的数据中,是:"defaultResult":"0.1"
然后,我将调试和测试的数据中的defaultResult的值,也修改为:0.1,之后再提交,然后接口就报了同样的异常,修改回"0.1",再提交又正常;看来问题就出在这里。
但是,为什么会出现这个问题呢?mongodb不可能不支持小数类型啊?而且mongodb中也有字段的值是小数的存在啊。
而且在以前的项目中,也有这样的请求数据,也不会报错,为什么现在会报错呢?
首先是怀疑是mongodb-java-driver版本问题,以前使用的是3.0.2的版本,现在是3.8.2,先将版本替换为原来的版本,系统不再报错,这样一来好像还真是版本有问题
但是后来为了验证一下这个问题,特意创建了一个验证项目,直接引入了3.8.2版本的mongodb-java-driver,然后使用相同的参数,并且将参数字符串转为了com.mongodb.BasicDBObject对象,
然后进行保存,发现保存成功了,那么这也就是说,并不是版本的原因,而报的错,最起码不是直接原因。
那到底是什么原因呢?
然后我就对比了两边的代码,发现最大的区别就在于,原项目中是将参数字符串转为了com.alibaba.fastjson.JSONObject对象,于是就在验证项目中修改了一下代码,
同样将参数转为com.alibaba.fastjson.JSONObject对象,然后执行,果然,就报出了期待中的“Prematurely reached end of stream”异常。
那么为什么使用com.mongodb.BasicDBObject对象就不报错,而使用com.alibaba.fastjson.JSONObject对象,就会报错呢?
由于报错的表现是对于一个字段值的类型的不同而导致的异常,那么就需要看一下,两种josn类转换后,究竟有什么不同,于是就写了判断字段值类型的代码:
if (dataJson.get("defaultResult") instanceof Double){
System.out.println("Double");
}else if (dataJson.get("defaultResult") instanceof java.math.BigDecimal){
System.out.println("BigDecimal");
}else if (dataJson.get("defaultResult") instanceof Float){
System.out.println("Float");
}else{
System.out.println("Float");
}
结果发现,二者的类型果然不同:
转换为com.mongodb.BasicDBObject对象时,defaultResult字段值的类型为:Double
转换为com.alibaba.fastjson.JSONObject对象时,defaultResult字段值的类型为:BigDecimal
至此,真正的原因就被找到了:
高版本的mongodb-java-driver,是支持高版本mongodb的新的数据类型的,在遇到BigDecimal的数据的时候,会自动的将数据转换为Decimal128类型,而Decimal128类型,是在3.4及以后的版本的新特性,
低版本中是不支持的,而当前使用的mongodb的版本比较低(2.8.0-rc5),所以在保存时,碰到了不支持的Decimal128类型,就会报错。
而由于转换为com.mongodb.BasicDBObject对象时,默认将小数转换为了Double类型,而Double类型是2.8.0-rc5版本所支持的类型,所以操作正常。
至于低版本的mongodb-java-driver,也是不支持高版本mongodb的新的数据类型的,在遇到BigDecimal的数据的时候,会自动的将数据转换为Double类型,所以操作也是正常的。