原文: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); }