読者です 読者をやめる 読者になる 読者になる

SpringMVC,MongoDBを使ってみたその6

ということで、今回MongoDBの例外処理です。

例外を故意に発生させてどのような動きになるか確認してみたいと思います。
とりあえず適当に一番下のような検証コードを実装してみました。
エラーを起こした結果、あれ?MongoExceptionは発生したけど、resultはNULLのままだ。
最初にWriteResultクラスのJavaDocを確認

This class lets you access the results of the previous write. if you have STRICT mode on, this just stores the result of that getLastError call if you don't, then this will actually do the getlasterror call. if another operation has been done on this connection in the interim, calls will fail

ちゃんと訳してないけど、getLastErrorメソッドがキーっぽいので、次にWriteResult#getLastErrorのメソッドを確認。
そこには、WriteConcernを引数に渡しているメソッドがありました。
ということでWriteConcernのJavaDocを確認。

WriteConcern control the write behavior for with various options, as well as exception raising on error conditions.
-1 = don't even report network errors
0 = default, don't call getLastError by default
1 = basic, call getLastError, but don't wait for slaves
2+= wait for slaves

コンストラクタの引数によって、エラーハンドリングが違うのね。
なんとなくの説明はわかるのですが、実際の動きとしてどう違うのか検証してみましょう。
検証内容としては、

  1. insertを実行するときに、無線LANの通信を切断する。(ネットワークエラー)
  2. insertを実行するときに、重複している_idをキーとする。

結果は以下のとおりでした。(はてなダイアリーの表の作り方が綺麗にできません。ごめんなさい)

ネットワークエラー
引数 例外発生 resultの値
-1 ×*1 Not Null
0 Null
1 Null
insert時の重複エラー
引数 例外発生 resultの値
-1 × Not Null
0 × Not Null
1 Null

resultの値がNotNullのところには、以下のようなエラーが入っているので、そこから値を取得して色々できると思うのですが、実際に使うときには、WriteConcernのコンストラクタに1もしくは2を渡して、きちんとエラーハンドリングをするべきかなと思います。

よかった…夏休みが終わるまでにちゃんと終わった。

resultの中身(toStringメソッド実行時のログ)

result->{ "err" : "E11000 duplicate key error index: mydb.servers.$_id_ dup key: { : ObjectId('4e5c430103648c41f6e669dc') }" , "code" : 11000 , "n" : 0 , "connectionId" : 842 , "ok" : 1.0}
DEBUG: jp.ne.hachi.dao.ServersDao - result error ->E11000 duplicate key error index: mydb.servers.$_id_ dup key: { : ObjectId('4e5c430103648c41f6e669dc') }

検証コードの抜粋

 public void save(ServerBean bean, DB db){
      DBCollection collection = db.getCollection(COLLECTION_NAME);
      WriteConcern w = new WriteConcern(); // ここは後で追加しました。
      WriteResult result = null;
      try{
           // 最初はwを渡さない状態で実行しています。  
           result = collection.insert(new BasicDBObject(bean.toMap()), w);
         
      }catch(MongoException e){
           logger.error(MarkerFactory.getMarker("test")  , e.getMessage(), e);
      }catch(Exception e ){
           logger.error(MarkerFactory.getMarker("test")  , e.getMessage(), e);
      }finally{
           if(logger.isDebugEnabled()){
                if(result != null){
                     CommandResult cr = result.getLastError();
                     logger.debug("result->"+ result.toString());
                     logger.debug("result error ->"+ result.getError());
                     logger.debug("cr->" + cr.toString());
                     logger.debug("cr is ok ? ->" + cr.ok());
                     logger.debug("cr exception->" + cr.getException());
                     logger.debug("cr message->" + cr.getErrorMessage());
                }else{
                     logger.debug("result-> null");
                }
           }
      }
 }

*1:◯:insertから例外が投げられる、×:例外が投げられない