|
based on v43 (2010-12-13更新) - オリジナル MongoDBは、 一つのドキュメント でのアトミックな操作をサポートしていますが、伝統的なロックと複雑なトランザクションを以下のいくつかの理由からサポートしていません。
MongoDBは、一つのドキュメントをアトミックに操作するための、下記に示すいくつかのメソッドをサポートしています。 modifierオペレーションMongoDBのアップデートコマンドは、いくつかの modifier をサポートしています。この操作ではドキュメントのエレメントをアトミックに更新します。次のものがあります。
これらのmodifierは、アトミックな実行をするのに使えます。 "値が変更されていなかったら更新"もう一つの、atomicにアップデートをする方法として、 "値が変更されていなかったら更新" という方法があります。
このオペレーションが失敗した場合には、最初のステップからやりなおします。 例えば、一つのオブジェクトをinventoryから取得したいとします。もしそのオブジェクトが存在する場合、取得したinventoryから1引きます。次のコードは、mongoシェルを使いこれをするためのコードです。(どの言語でも同じようなファンクションがあるでしょう) > 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} // 成功
上記の例では、skuから実際に1引けるかどうかというのを考えていません。そのため下のコードの方が優れていますが汎用性は低いです。 modifierオペレーション ($inc) を使います。一般的なアップデートに関して($incを使えないような)は、上記の"値が変更されていなかったら更新"の方法が推奨されます。 > t.update({sku:"abc",qty:{$gt:0}}, { $inc : { qty : -1 } } ) ; db.$cmd.findOne({getlasterror:1})
{"err" : , "updatedExisting" : true , "n" : 1 , "ok" : 1} // 成功
> t.update({sku:"abcz",qty:{$gt:0}}, { $inc : { qty : -1 } } ) ; db.$cmd.findOne({getlasterror:1})
{"err" : , "updatedExisting" : false , "n" : 0 , "ok" : 1} // 失敗
ABA問題上記の最初の例で、"もし qty が変化していなかったらオブジェクトを更新" ということをしました。しかし、 sku が更新されてたらどうでしょう。 その変更を上書きし、消してしまいます。 この 問題 を防ぐいくつかの方法があります。基本的には、単純にそのことに気づくことです。
"存在していなかったらインサート"もう一つの楽観的な並列処理として、存在しない場合だけインサートする、という方法があります。これは、条件に対してユニークインデックスを持っている場合にだけ可能です。次の例は、この方法を使って、_idを単純に増やしながらインサートする例です。 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してmodify(またはremove)findAndModifyコマンドドキュメント を参照してください。 複数のオブジェクトを同時に更新すべての対象のドキュメントに対してmulti-updateを行なうことができます。デフォルトでは、multi-updateは他の操作が割り込むことを許します。そのためこれは真のアトミックな操作ではありません。完全にisolatedに実行するには、 $atomic をつけます。 (訳注: multi-updateとは、updateで複数のオブジェクトを更新するもの。4つ目の引数で指定する) isolatedではない:
db.foo.update( { x : 1 } , { $inc : { y : 1 } } , false , true );
isolated:
db.foo.update( { x : 1 , $atomic : 1 } , { $inc : { y : 1 } } , false , true );
|

IF YOU HAVE A QUESTION, POST IT TO THE USER GROUP.
These pages are fine for comments, but for questions, your best bet will always be the MongoDB User Group. blog comments powered by Disqus