mongodb2升级到mongodb3.4思路

41 篇文章 1 订阅

环境

mongodb库:2.4、2.6
驱动包:
mongodb-driver-2.11.3.jar

mongodb-driver-3.4.2.jar
bson-3.4.2.jar
mongodb-driver-core-3.4.2.jar

情形

使用mongodb驱动包为2.11的写法:

    DBCollection collection = db.getCollection("gg_module_access_statistics");

    BasicDBObject fields = new BasicDBObject();
    fields.append("address", 1);
    BasicDBObject query = new BasicDBObject();
    query.append("status", 1);
    DBCursor cursor = collection.find(query, fields).limit(10);

    while(cursor.hasNext()){
        DBObject o = cursor.next();
        System.out.println(o.get("address"));
    }
    cursor.close();

使用驱动包mongodb-driver-3.4.2中写法为:

FindIterable<Document> findIterable = collection.find().limit(10);
//这一步开始查询数据库
MongoCursor<Document> iterator = findIterable.iterator();
while(iterator.hasNext()){
    Document o = iterator.next();
    System.out.println(o.get("address"));
}
iterator.close();

可以看出mongodb-driver-2.11版本的写法是:

1、遍历的是游标,DBCursor
DBCursor cursor = collection.find(new BasicDBObject(), fields).limit(10);

2、游标的元素是DBObject类型的
DBObject o = cursor.next();

3、当从mongodb数据库中读取数组时,默认是BasicDBLIst类型的。

而在mongodb-driver-3.4版本中:

1、遍历的是迭代器FindIterable。
FindIterable<Document> findIterable = collection.find().limit(10);
MongoCursor<Document> iterator = findIterable.iterator();

2、游标的元素是Document类型
Document o = iterator.next();

3、当从mongodb数据中读取数组时,默认是ArrayList类型。

思路

刚开始我看到上区别后,我得出结果,我们公司永远都不可能升级成mongodb3+
能得出这样的结论,真的说明我对java封装思想理解不够。公司的后端架构师把3.4中的DocumentIterable等都封装起来。比如以前2.4中写法是BasicDBObjectDBCursor,那么就把它们(Document等)封装进去。这样就可以做到从2.4版本升级到3.4的版本啦。
就贴一张公司封装图片:

这里写图片描述

总之假设不想更改现有的代码,又想升级到mongodb3.4那就是把3.4中新写法都封装起来,封装的类名就是以前2.4中的类名。只不过封装好了之后需要重新引入包(也就是对着项目名 按:ctrl + shift + o)。

BasicDBList

这个数组在驱动包2.4中默认数组,也就是mongodb库中的数组都会被转成这个类型。
但是在驱动包3.4中,已不是它啦,而是javaArrayList类型。

在驱动包mongodb2.4
这里写图片描述

在驱动包mongodb3.4

这里写图片描述

之所以这一块单独讲是因为,公司昨天在替换包时,发现有这么一段代码(强制类型转换):

while(cursor.hasNext()){

    DBObject o = cursor.next();
    System.out.println((BasicDBList)o.get("G3_01_01_02_access_account"));
    //同事为了BasicDBList中Iterable方法而做了这样一个强转,结果在本次驱动包升级时
    //出现了bug,虽然你可以说是驱动包兼容不好,但是这种强转本身就不对。
}

因为驱动包3.4现在使用的是ArrayList而不是BasicDBList,所以就报错啦!
这里也告诉我们,以后再做类型转换时,能转成java本身类型就转java本身类型。不要因为框架类型的某些特性而选择框架自己的类型。mongodb驱动包2.4与3.4就是一个活生生的例子。框架本身就是基本java语法,理论上,框架能做到的,java本身语法一定能做到。

源码

昨天非常想知道源码是怎么实现的。(一直找到凌晨12点半,明天还得上班)

所以去官网把相应的源码都下载下来了,再在eclipse中关联下。
源码包名:

bson-3.4.2-sources.jar
mongodb-driver-core-3.4.2-sources.jar
mongo-java-driver-3.4.2-sources.jar

驱动包官网:https://oss.sonatype.org/content/repositories/releases/org/mongodb/

经过我一路断点,终于找到了具体实现的代码。
具体是在bson-3.4.2这个包中:

这里写图片描述


其中的readValue()方法:

这里写图片描述

这里我把具体代码贴出来:

private Object readValue(final BsonReader reader, final DecoderContext decoderContext) {
        BsonType bsonType = reader.getCurrentBsonType();
        if (bsonType == BsonType.NULL) {
            reader.readNull();
            return null;
        } else if (bsonType == BsonType.ARRAY) {//数组就走这里
            return readList(reader, decoderContext);
        } else if (bsonType == BsonType.BINARY && BsonBinarySubType.isUuid(reader.peekBinarySubType()) && reader.peekBinarySize() == 16) {//从3.4开始支持对UUID处理
            return registry.get(UUID.class).decode(reader, decoderContext);
        }
        return valueTransformer.transform(bsonTypeCodecMap.get(bsonType).decode(reader, decoderContext));
    }
//如果是数组,就会调用这个方法
private List<Object> readList(final BsonReader reader, final DecoderContext decoderContext) {
        reader.readStartArray();
        List<Object> list = new ArrayList<Object>();//就在这里了
        while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
            list.add(readValue(reader, decoderContext));
        }
        reader.readEndArray();
        return list;
    }

我们再看到这样一段代码:

return valueTransformer.transform(bsonTypeCodecMap.get(bsonType).decode(reader, decoderContext));

重点是decode(reader, decoderContext)decode()方法。

这里写图片描述

如果是Long类型:

public class LongCodec implements Codec<Long> {
    @Override
    public void encode(final BsonWriter writer, final Long value, final EncoderContext encoderContext) {
        writer.writeInt64(value);
    }

    @Override
    public Long decode(final BsonReader reader, final DecoderContext decoderContext) {
        return reader.readInt64();//就会调用这个方法
    }

    @Override
    public Class<Long> getEncoderClass() {
        return Long.class;
    }
}

readInt64()方法:

    @Override
    public long readInt64() {
        checkPreconditions("readInt64", BsonType.INT64);
        setState(getNextState());
        return doReadInt64();
    }

这里写图片描述

doReadInt64源码:

 @Override
    protected long doReadInt64() {
        return bsonInput.readInt64();
    }

readInt64源码:

@Override
    public long readInt64() {
        ensureOpen();
        ensureAvailable(8);
        return buffer.getLong();
    }

这里写图片描述

getLong()源码:

    @Override
    public long getLong() {
        return buf.getLong();
    }

这里写图片描述

getLong()源码:

public long getLong() {
        return Bits.getLong(this, ix(nextGetIndex(8)), bigEndian);
    }
static long getLong(ByteBuffer bb, int bi, boolean bigEndian) {
        return bigEndian ? getLongB(bb, bi) : getLongL(bb, bi);
    }
static long getLongB(ByteBuffer bb, int bi) {
        return makeLong(bb._get(bi    ),
                        bb._get(bi + 1),
                        bb._get(bi + 2),
                        bb._get(bi + 3),
                        bb._get(bi + 4),
                        bb._get(bi + 5),
                        bb._get(bi + 6),
                        bb._get(bi + 7));
    }
// -- get/put long --

    static private long makeLong(byte b7, byte b6, byte b5, byte b4,
                                 byte b3, byte b2, byte b1, byte b0)
    {
        return ((((long)b7       ) << 56) |
                (((long)b6 & 0xff) << 48) |
                (((long)b5 & 0xff) << 40) |
                (((long)b4 & 0xff) << 32) |
                (((long)b3 & 0xff) << 24) |
                (((long)b2 & 0xff) << 16) |
                (((long)b1 & 0xff) <<  8) |
                (((long)b0 & 0xff)      ));
    }

这里的bufByteBuffer类型,ByteBufferjava.nio.ByteBuffer。到这这里我们知道了,mongodb3.4驱动包底层是使用java nio技术。nio是非阻塞输入输出流。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山鬼谣me

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值