|
MongoDB supports atomic operations on single documents. MongoDB does not support traditional locking and complex transactions for a number of reasons:
MongoDB does support several methods of manipulating single documents atomically, which are detailed below. Modifier operationsThe Mongo DB update command supports several modifiers, all of which atomically update an element in a document. They include:
These modifiers are convenient ways to perform certain operations atomically. "Update if Current"Another strategy for atomic updates is "Update if Current". This is what an OS person would call Compare and Swap. For this we
Should the operation fail, we might then want to try again from step 1. For example, suppose we wish to fetch one object from inventory. We want to see that an object is available, and if it is, deduct it from the inventory. The following code demonstrates this using mongo shell syntax (similar functions may be done in any language): > t=db.inventory
> s = t.findOne({sku:'abc'})
{"_id" : "49df4d3c9664d32c73ea865a" , "sku" : "abc" , "qty" : 30}
> qty_old = s.qty;
> --s.qty;
> t.update({_id:s._id, qty:qty_old}, s); db.$cmd.findOne({getlasterror:1});
{"err" : , "updatedExisting" : true , "n" : 1 , "ok" : 1} // it worked
For the above example, we likely don't care the exact sku quantity as long as it is as least as great as the number to deduct. Thus the following code is better, although less general -- we can get away with this as we are using a predefined modifier operation ($inc). For more general updates, the "update if current" approach shown above is recommended. > t.update({sku:"abc",qty:{$gt:0}}, { $inc : { qty : -1 } } ) ; db.$cmd.findOne({getlasterror:1})
{"err" : , "updatedExisting" : true , "n" : 1 , "ok" : 1} // it worked
> t.update({sku:"abcz",qty:{$gt:0}}, { $inc : { qty : -1 } } ) ; db.$cmd.findOne({getlasterror:1})
{"err" : , "updatedExisting" : false , "n" : 0 , "ok" : 1} // did not work
The ABA NuanceIn the first of the examples above, we basically did "update object if qty is unchanged". However, what if since our read, sku had been modified? We would then overwrite that change and lose it! There are several ways to avoid this problem ; it's mainly just a matter of being aware of the nuance.
"Insert if Not Present"Another optimistic concurrency scenario involves inserting a value when not already there. When we have a unique index constraint for the criteria, we can do this. The following example shows how to insert monotonically increasing _id values into a collection using optimistic concurrency: function insertObject(o) {
x = db.myCollection;
while( 1 ) {
// determine next _id value to try
var c = x.find({},{_id:1}).sort({_id:-1}).limit(1);
var i = c.hasNext() ? c.next()._id + 1 : 1;
o._id = i;
x.insert(o);
var err = db.getLastErrorObj();
if( err && err.code ) {
if( err.code == 11000 /* dup key */ )
continue;
else
print("unexpected error inserting data: " + tojson(err));
}
break;
}
}
Find and Modify (or Remove)See the findandmodify Command documentation for more information. Applying to Multiple Objects AtomicallyYou can use multi-update to apply the same modifier to each object. This will be pseudo-atomic by default. Its one operation, but occasonaly someone else can get it. To make it full atomic you can use $atomic non atomic db.foo.update( { x : 1 } , { $inc : { y : 1 } } , false , true );
atomic db.foo.update( { x : 1 , $atomic : 1 } , { $inc : { y : 1 } } , false , true );
|

PLEASE POST QUESTIONS IN THE USER GROUPS FORUM. Post non-question comments and helpful hints here.
blog comments powered by Disqus