MongoDB 原子操作(findAndModify)
<p> </p><p>原文: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</p>
<p> </p>
<div class="cnblogs_code">
<pre>
<span style="color: rgba(0, 0, 255, 1)">public</span> Booking updateOrderQty(String bookingNo, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> ecOrderQty, String bookingGmtTime) {
Query query </span>= Query.query(Criteria.<span style="color: rgba(0, 0, 255, 1)">where</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">bookingNo</span><span style="color: rgba(128, 0, 0, 1)">"</span>).<span style="color: rgba(0, 0, 255, 1)">is</span><span style="color: rgba(0, 0, 0, 1)">(bookingNo));
Update update </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Update().<span style="color: rgba(0, 0, 255, 1)">set</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ecOrderQty</span><span style="color: rgba(128, 0, 0, 1)">"</span>, ecOrderQty).<span style="color: rgba(0, 0, 255, 1)">set</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">status</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">P</span><span style="color: rgba(128, 0, 0, 1)">"</span>).<span style="color: rgba(0, 0, 255, 1)">set</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">bookingTime</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, bookingGmtTime);
getTemplate().updateFirst(query, update, Booking.</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> getTemplate().findOne(query, Booking.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
}</span></pre>
</div>
<p> </p>
<p><strong>MongoDB 原子操作</strong></p>
<p>mongodb不支持事务(4.1支持),所以,在你的项目中应用时,要注意这点。无论什么设计,都不要要求mongodb保证数据的完整性。</p>
<p>但是mongodb提供了许多原子操作,比如文档的保存,修改,删除等,都是原子操作。</p>
<p>所谓原子操作就是要么这个文档保存到Mongodb,要么没有保存到Mongodb,不会出现查询到的文档没有保存完整的情况</p>
<p> </p>
<p><strong>原子操作数据模型</strong></p>
<p>考虑下面的例子,图书馆的书籍及结账信息。</p>
<p>实例说明了在一个相同的文档中如何确保嵌入字段关联原子操作(update:更新)的字段是同步的。</p>
<div class="cnblogs_code">
<pre>book =<span style="color: rgba(0, 0, 0, 1)"> {
_id: </span><span style="color: rgba(128, 0, 128, 1)">123456789</span><span style="color: rgba(0, 0, 0, 1)">,
title: </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">MongoDB: The Definitive Guide</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
author: [ </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Kristina Chodorow</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Mike Dirolf</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> ],
published_date: ISODate(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">2010-09-24</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">),
pages: </span><span style="color: rgba(128, 0, 128, 1)">216</span><span style="color: rgba(0, 0, 0, 1)">,
language: </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">English</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
publisher_id: </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">oreilly</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
available: </span><span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">,
checkout: [ { by: </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">joe</span><span style="color: rgba(128, 0, 0, 1)">"</span>, date: ISODate(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">2012-10-15</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">) } ]
}</span></pre>
</div>
<p> </p>
<p>你可以使用 db.collection.findAndModify() 方法来判断书籍是否可结算并更新新的结算信息。</p>
<p>在同一个文档中嵌入的 available 和 checkout 字段来确保这些字段是同步更新的:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)"> db.books.findAndModify ( {
query: {
_id: </span><span style="color: rgba(128, 0, 128, 1)">123456789</span><span style="color: rgba(0, 0, 0, 1)">,
available: { $gt: </span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)"> }
},
update: {
$inc: { available: </span>-<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)"> },
$push: { checkout: { by: </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">abc</span><span style="color: rgba(128, 0, 0, 1)">"</span>, date: <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Date() } }
}
} )</span></pre>
</div>
<p> </p>
<p> </p>
<p><strong>findAndModify函数的介绍</strong><br>findAndModify执行<span style="color: rgba(51, 153, 234, 1)">分为find和update两步,属于<span style="color: rgba(51, 153, 234, 1)">get-and-set式的操作,它的功能强大之处在于可以<span style="color: rgba(243, 59, 69, 1)">保证操作的原子性。<br> findAndModify对于操作查询以及执行其它需要取值和赋值风格的原子性操作是十分方便的,使用它可以实现一些简单的类事务操作。</span></span></span></p>
<p>MongoOperations.java源码</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* Triggers <a href="</span><span style="color: rgba(0, 128, 0, 1); text-decoration: underline">https://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/</span><span style="color: rgba(0, 128, 0, 1)">">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.
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
@Nullable
</span><T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass);</pre>
</div>
<p>MongoTemplate.java 源码</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)"> @Nullable
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T><span style="color: rgba(0, 0, 0, 1)"> entityClass) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> findAndModify(query, update, options, entityClass, determineCollectionName(entityClass));
}
@Nullable
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T><span style="color: rgba(0, 0, 0, 1)"> entityClass,
String collectionName) {
Assert.notNull(query, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Query must not be null!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
Assert.notNull(update, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Update must not be null!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
Assert.notNull(options, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Options must not be null!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
Assert.notNull(entityClass, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">EntityClass must not be null!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
Assert.notNull(collectionName, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">CollectionName must not be null!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
FindAndModifyOptions optionsToUse </span>=<span style="color: rgba(0, 0, 0, 1)"> FindAndModifyOptions.of(options);
Optionals.ifAllPresent(query.getCollation(), optionsToUse.getCollation(), (l, r) </span>-><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> IllegalArgumentException(
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Both Query and FindAndModifyOptions define a collation. Please provide the collation only via one of the two.</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
});
query.getCollation().ifPresent(optionsToUse::collation);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> doFindAndModify(collectionName, query.getQueryObject(), query.getFieldsObject(),
getMappedSortObject(query, entityClass), entityClass, update, optionsToUse);
}
</span><span style="color: rgba(0, 0, 255, 1)">protected</span> <T><span style="color: rgba(0, 0, 0, 1)"> T doFindAndModify(String collectionName, Document query, Document fields, Document sort,
Class</span><T><span style="color: rgba(0, 0, 0, 1)"> entityClass, Update update, @Nullable FindAndModifyOptions options) {
EntityReader</span><? super T, Bson> readerToUse = <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.mongoConverter;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (options == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
options </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FindAndModifyOptions();
}
MongoPersistentEntity</span><?> entity =<span style="color: rgba(0, 0, 0, 1)"> mappingContext.getPersistentEntity(entityClass);
increaseVersionForUpdateIfNecessary(entity, update);
Document mappedQuery </span>=<span style="color: rgba(0, 0, 0, 1)"> queryMapper.getMappedObject(query, entity);
Document mappedUpdate </span>=<span style="color: rgba(0, 0, 0, 1)"> updateMapper.getMappedObject(update.getUpdateObject(), entity);
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (LOGGER.isDebugEnabled()) {
LOGGER.debug(
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">findAndModify using query: {} fields: {} sort: {} for class: {} and update: {} </span><span style="color: rgba(128, 0, 0, 1)">"</span> + <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">in collection: {}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
serializeToJsonSafely(mappedQuery), fields, sort, entityClass, serializeToJsonSafely(mappedUpdate),
collectionName);
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span> executeFindOneInternal(<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FindAndModifyCallback(mappedQuery, fields, sort, mappedUpdate, options),
</span><span style="color: rgba(0, 0, 255, 1)">new</span> ReadDocumentCallback<T><span style="color: rgba(0, 0, 0, 1)">(readerToUse, entityClass, collectionName), collectionName);
}</span></pre>
</div>
<p> </p><br><br>
来源:https://www.cnblogs.com/lshan/p/14097223.html
頁:
[1]