質問です。

527 views
Skip to first unread message

h_hoshino

unread,
Sep 13, 2012, 4:12:34 AM9/13/12
to mongo...@googlegroups.com
はじめまして。h_hoshinoと申します。
Mongoを始めてばかりで、わからないことがあるので質問させて下さい。
PHPのアプリ上からinsertまたは、updateを実行した場合に意図してコミットを行うことは可能でしょうか?
また、行うことができない場合にどのタイミングで行われるか教えてく下さい。

岩崎晃司

unread,
Sep 13, 2012, 4:19:02 AM9/13/12
to mongo...@googlegroups.com
岩崎 @madapaja です。

コミットというのが、データがディスク上に書き込まれる事だとすると、
MongoCollection::saveメソッドで、オプションを渡すことで可能です。

$collection->save($data, array('fsync' => true));

詳細はPHPマニュアルで確認してください。
http://jp.php.net/manual/ja/mongocollection.save.php

また、fsyncを指定しなかった場合などのディスクへ同期されるタイミングの説明は、
MongoDBマニュアルにありますのでそちらをご参照ください。
http://jp.docs.mongodb.org/manual/faq/developers/#when-does-mongodb-write-updates-to-disk

以上、簡単ですが参考まで。
----
岩崎晃司
iwa...@cresc.com


2012年9月13日 17:12 h_hoshino <gurensub...@gmail.com>:
> --
> このメールは Google グループのグループ「MongoDB JP」の登録者に送られています。
> このディスカッションをウェブ上で閲覧するには、https://groups.google.com/d/msg/mongodb-jp/-/PB5CDX9HEVUJ
> にアクセスしてください。
> このグループに投稿するには、mongo...@googlegroups.com にメールを送信してください。
> このグループから退会するには、mongodb-jp+...@googlegroups.com にメールを送信してください。
> 詳細については、http://groups.google.com/group/mongodb-jp?hl=ja からこのグループにアクセスしてください。

岩崎晃司

unread,
Sep 13, 2012, 4:23:19 AM9/13/12
to mongo...@googlegroups.com
岩崎 @madapaja です。

すみません。少し抜けた部分があったので訂正します。

> MongoCollection::saveメソッドで、オプションを渡すことで可能です。

fsyncオプションは、saveメソッドのみではなく、
insert/update/remove メソッドなどでも同様に指定できます。

2012年9月13日 17:19 岩崎晃司 <iwa...@cresc.com>:

crumbjp

unread,
Sep 13, 2012, 9:30:18 PM9/13/12
to mongo...@googlegroups.com
窪田@crumbjpです。

MongoDBは所謂RDBMSでは無く、トランザクションという概念がありません。
したがって、commitやrollbackなどの概念もありません。

発行したクエリは基本的に即時反映されます。

排他制御に関してもアプリケーションが管理する他ありません。
これらの機能を犠牲にして分散性を求めたプロダクトとも言えます。

機能的には物足りないと思うかもしれませんが
現実はWEBサイトでRDBMSのトランザクションは使い辛いので問題に成り難いのです。

MemcachedのCAS相当のクエリはこんな感じです。

$updateData = $mongoCollection->findOne(...);
$updateData[$foo] = $bar;
$cond = array( '_rev' => $updateData['_rev'] , '_id' => $updateData['_id'] );
$updateData['_rev'] = time(); // 衝突が怖ければ+= 1 でも良い。
$mongoCollection->update(  $cond , array('$set' => $arg) , array('upsert' => true , 'safe' => true , 'fsync' => true) );

h_hoshino

unread,
Sep 13, 2012, 11:55:01 PM9/13/12
to mongo...@googlegroups.com
岩崎さん、窪田さん

h_hoshinoです。
ご回答ありがとうございます。

Kei Funagayama

unread,
Sep 13, 2012, 11:55:21 PM9/13/12
to mongo...@googlegroups.com
船ヶ山@fkeiです。

他の方が述べられているように、MongoDBにはトランザクションという概念はありません。
ですが、Atomic Updateというものがあるので、確実にデータ更新を完了及び確認できる方法は存在します。

1.ディスク書き込みまで保証する場合
岩崎さんが述べられているように{fsync:1}をクエリーに追加することで実現可能です。


2.ディスクには書き込まれないが、メモリ書き込みまで保証する場合
高速に更新処理をおこなうため、MongoDBはデフォルトでは更新処理の成否結果を受け取りません。ですが、{safe:true}をクエリーに追加することで、更新結果(getlasterror)を取得することが可能です。
※version 1.6? 1.8 からoplogをサポートしているので、通常はfsyncまでやらずともsafe:trueで十分だと思います。


3. N台以上にレプリケーションされるまでを保証する場合
wオプションを指定することで保証する事が可能です。


補足ですが、検索してヒットしたオブジェクトを更新する場合は、findAndModifyが有効だと思います。findAndModifyがAtomic Updateですので、参照更新が一度に行えます。

このページにわかりやすく書かれているので一読して見ることをおすすめします。



ippei

unread,
Sep 15, 2012, 1:22:15 PM9/15/12
to mongo...@googlegroups.com

こんにちは、雲屋の鈴木いっぺいです。


窪田@crumbjp さんや、船ヶ山@fkei さんの仰られる様に、MongoDBはトランザクションの概念も無く、従って、コミットする、という機能もありません。そう言い切ってしまうと本当に使い物になるのか、という疑問がつい立ってしまいますが、元々MongoDBの作りとして、投入されたデータの書き込みの後は約束され、次の読み/書きにちゃんと前の書きが反映されたデータが保証される、という構造になってます。


ただ、本当に書き込みが保証されている事を確認すると共に、必要に応じてロールバックも施したい、という場合は、MongoDBの2フェーズコミット機能を利用する方法もあるかと思います。

http://jp.docs.mongodb.org/manual/tutorial/perform-two-phase-commits/

基本的に複数のドキュメントの同期を保証する時に便利な機能ですが、ご検討いただければ幸いです。


さらに、書き込みがちゃんと成功しているかどうかを確認する方法として、getLastErrorコマンドを利用する事もできます。

ここにそのコマンド詳細が記載されています(英語)

http://api.mongodb.org/wiki/current/getLastError%20Command.html


PHPの場合は、insertを実行する際に、PHPドライバーの"safe"オプションを利用する事で使えます。

http://it.php.net/manual/en/mongocollection.insert.php

もちろん、PHPに限らず、他の言語でも対応できるはずです。

小生は、アメリカの方のmongodb-userというgoogle groupに参加していて、このご質問をそちらに飛ばして回答を数名から頂いてます。また、何かありましたらそのような方法でアメリカのユーザグループとの接点を作っていきたいと思ってますのでよろしくお願いします(レスポンスに時間がかかる場合もありますがご了承くださいね)。

Masahiro Nakagawa

unread,
Sep 15, 2012, 7:33:44 PM9/15/12
to mongo...@googlegroups.com
repeatedlyです.


2012/9/16 ippei <suz...@kumoya.co.jp>:
>
[snip]
>
> ただ、本当に書き込みが保証されている事を確認すると共に、必要に応じてロールバックも施したい、という場合は、MongoDBの2フェーズコミット機能を利用する方法もあるかと思います。
>
> http://jp.docs.mongodb.org/manual/tutorial/perform-two-phase-commits/
>
> 基本的に複数のドキュメントの同期を保証する時に便利な機能ですが、ご検討いただければ幸いです。

これはMongoDBに2phase commit機能サポートがあるというわけではなく,自分で2phase
commitっぽいのを実装する,というので合っていますか?「MongoDBの2フェーズコミット機能を利用する」という表現が気になりました

Suzuki Ippei

unread,
Sep 15, 2012, 8:11:48 PM9/15/12
to mongo...@googlegroups.com
repeatedlyさん、

マニュアルを見ての通り、記載している手順に従って、ちゃんとした2 phase commitの機能に加え、Rollbackの機能もちゃんと実装する事ができるようです。(RollBackのやり方は指定する必要がありますが)
ただ、このマニュアルに記載されているのは、複数のドキュメントに対する読み書きにきちんと整合性をもたせるためのプログラミング手法を解説してます。事例は非常に簡単なもので、単一のアプリケーションが2つの銀行口座間のお金を移動させる際に必要となる2 phase commitのプログラミングです。

リアルな世界では、
- 複数のアプリケーションが同じアカウントにアクセスする際の整合性配慮
- PendingからDoneに移行する際の明確な条件をアプリケーションの要件に従って規定する(例:口座の残高がマイナスになったときの問題対処)
- ジャーナルを並行して作り、障害の際のリカバリに利用する
- Write concernと言って書き込みを行った際にちゃんと完了しているかどうかの確認をどれだけマメに行うか(getLastError等)
等、色々と配慮が必要になります。これは基本的にこのマニュアルに記載されている2 phase commitの機能の外とされており、個別に対応する必要があります。
> --
> このメールは Google グループのグループ「MongoDB JP」の登録者に送られています。
Reply all
Reply to author
Forward
0 new messages