MongoDB 原子操作(findAndModify)

原文:https://blog.csdn.net/weixin_41888813/article/details/96118703?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control

   
    public Booking updateOrderQty(String bookingNo, int ecOrderQty, String bookingGmtTime) {
        Query query = Query.query(Criteria.where("bookingNo").is(bookingNo));
        Update update = new Update().set("ecOrderQty", ecOrderQty).set("status", "P").set("bookingTime", bookingGmtTime);
        getTemplate().updateFirst(query, update, Booking.class);
        return getTemplate().findOne(query, Booking.class);
    }

MongoDB 原子操作

mongodb不支持事务(4.1支持),所以,在你的项目中应用时,要注意这点。无论什么设计,都不要要求mongodb保证数据的完整性。

但是mongodb提供了许多原子操作,比如文档的保存,修改,删除等,都是原子操作。

所谓原子操作就是要么这个文档保存到Mongodb,要么没有保存到Mongodb,不会出现查询到的文档没有保存完整的情况

原子操作数据模型

考虑下面的例子,图书馆的书籍及结账信息。

实例说明了在一个相同的文档中如何确保嵌入字段关联原子操作(update:更新)的字段是同步的。

book = {
          _id: 123456789,
          title: "MongoDB: The Definitive Guide",
          author: [ "Kristina Chodorow", "Mike Dirolf" ],
          published_date: ISODate("2010-09-24"),
          pages: 216,
          language: "English",
          publisher_id: "oreilly",
          available: 3,
          checkout: [ { by: "joe", date: ISODate("2012-10-15") } ]
        }

你可以使用 db.collection.findAndModify() 方法来判断书籍是否可结算并更新新的结算信息。

在同一个文档中嵌入的 available 和 checkout 字段来确保这些字段是同步更新的:

    db.books.findAndModify ( {
       query: {
                _id: 123456789,
                available: { $gt: 0 }
              },
       update: {
                 $inc: { available: -1 },
                 $push: { checkout: { by: "abc", date: new Date() } }
               }
    } )

findAndModify函数的介绍
findAndModify执行分为find和update两步,属于get-and-set式的操作,它的功能强大之处在于可以保证操作的原子性。
findAndModify对于操作查询以及执行其它需要取值和赋值风格的原子性操作是十分方便的,使用它可以实现一些简单的类事务操作。

MongoOperations.java源码

    /**
     * Triggers <a href="https://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/">findAndModify
     * <a/> to apply provided {@link Update} on documents matching {@link Criteria} of given {@link Query} taking
     * {@link FindAndModifyOptions} into account.
     *
     * @param query the {@link Query} class that specifies the {@link Criteria} used to find a record and also an optional
     *          fields specification.
     * @param update the {@link Update} to apply on matching documents.
     * @param options the {@link FindAndModifyOptions} holding additional information.
     * @param entityClass the parametrized type.
     * @return the converted object that was updated or {@literal null}, if not found. Depending on the value of
     *         {@link FindAndModifyOptions#isReturnNew()} this will either be the object as it was before the update or as
     *         it is after the update.
     */
    @Nullable
    <T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass);

MongoTemplate.java 源码

    @Nullable
    @Override
    public <T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass) {
        return findAndModify(query, update, options, entityClass, determineCollectionName(entityClass));
    }
     
     
    @Nullable
    @Override
    public <T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass,
                               String collectionName) {
     
        Assert.notNull(query, "Query must not be null!");
        Assert.notNull(update, "Update must not be null!");
        Assert.notNull(options, "Options must not be null!");
        Assert.notNull(entityClass, "EntityClass must not be null!");
        Assert.notNull(collectionName, "CollectionName must not be null!");
     
        FindAndModifyOptions optionsToUse = FindAndModifyOptions.of(options);
     
        Optionals.ifAllPresent(query.getCollation(), optionsToUse.getCollation(), (l, r) -> {
            throw new IllegalArgumentException(
                "Both Query and FindAndModifyOptions define a collation. Please provide the collation only via one of the two.");
        });
     
        query.getCollation().ifPresent(optionsToUse::collation);
     
        return doFindAndModify(collectionName, query.getQueryObject(), query.getFieldsObject(),
            getMappedSortObject(query, entityClass), entityClass, update, optionsToUse);
    }
     
     
    protected <T> T doFindAndModify(String collectionName, Document query, Document fields, Document sort,
                                    Class<T> entityClass, Update update, @Nullable FindAndModifyOptions options) {
     
        EntityReader<? super T, Bson> readerToUse = this.mongoConverter;
     
        if (options == null) {
            options = new FindAndModifyOptions();
        }
     
        MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
     
        increaseVersionForUpdateIfNecessary(entity, update);
     
        Document mappedQuery = queryMapper.getMappedObject(query, entity);
        Document mappedUpdate = updateMapper.getMappedObject(update.getUpdateObject(), entity);
     
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(
                "findAndModify using query: {} fields: {} sort: {} for class: {} and update: {} " + "in collection: {}",
                serializeToJsonSafely(mappedQuery), fields, sort, entityClass, serializeToJsonSafely(mappedUpdate),
                collectionName);
        }
     
        return executeFindOneInternal(new FindAndModifyCallback(mappedQuery, fields, sort, mappedUpdate, options),
            new ReadDocumentCallback<T>(readerToUse, entityClass, collectionName), collectionName);
    }
原文地址:https://www.cnblogs.com/lshan/p/14097223.html