DBAPILayer 繼承了抽象類 DB ,主要借助內部類 DBApiLayer.MyCollection 實現具體的數據庫操作。
DB 類的介紹可以參考:
http://xxing22657-yahoo-com-cn.iteye.com/blog/1291183
借助 DBApiLayer.MyCollection 實現增刪改查
DBApiLayer.MyCollection 繼承了抽象類 DBCollection,具體實現了增刪改查操作。
DBCollection 類的介紹可以參考之前的文章:
http://xxing22657-yahoo-com-cn.iteye.com/blog/1255181
增刪改查操作的方法聲明如下:
// 插入操作
protected WriteResult insert(DBObject[] arr, boolean shouldApply , com.mongodb.WriteConcern concern )
// 刪除操作
public WriteResult remove( DBObject o , com.mongodb.WriteConcern concern )
// 查找操作
Iterator<DBObject> __find( DBObject ref , DBObject fields , int numToSkip , int batchSize, int limit , int options )
// 更新操作
public WriteResult update( DBObject query , DBObject o , boolean upsert , boolean multi , com.mongodb.WriteConcern concern )
這些操作都需要借助 DBTCPConnector 的 say 方法和 call 方法,這兩個方法的實現可以參考這篇文章:
http://xxing22657-yahoo-com-cn.iteye.com/blog/1416331
下面以 insert 和 _find 操作為例進行分析
// 插入操作
protected WriteResult insert(DBObject[] arr, boolean shouldApply , com.mongodb.WriteConcern concern )
throws MongoException {
// 輸出跟蹤信息
if ( willTrace() ) {
for (DBObject o : arr) {
trace( "save: " + _fullNameSpace + " " + JSON.serialize( o ) );
}
}
// 是否更新對應的DBObject
if ( shouldApply ){
for ( int i=0; i<arr.length; i++ ){
DBObject o=arr[i];
apply( o );
_checkObject( o , false , false );
Object id = o.get( "_id" );
if ( id instanceof ObjectId ){
((ObjectId)id).notNew();
}
}
}
WriteResult last = null;
// 輸出 DBObject 到 Mongo 服務器
int cur = 0;
int maxsize = _mongo.getMaxBsonObjectSize();
while ( cur < arr.length ){
OutMessage om = new OutMessage( _mongo , 2002 );
// 以 0 作為交互開始的信號
om.writeInt( 0 ); // reserved
// 輸出完整的 namespace
om.writeCString( _fullNameSpace );
// 將要輸出的對象寫入 OutMessage
for ( ; cur<arr.length; cur++ ){
DBObject o = arr[cur];
om.putObject( o );
// 一次批量插入數據量的上限是 maxBsonObjectSize 的 4 倍
// 安全起見,這里使用 maxBsonObjectSize 的兩倍
if ( om.size() > 2 * maxsize ){
// 超出一次批量插入的限制
// 停止構造 OutMessage,準備進入下一個循環
cur++;
break;
}
}
// 調用 DBTCPConnector 的 say 方法執行寫入
last = _connector.say( _db , om , concern );
}
return last;
}
// 查找操作
Iterator<DBObject> __find( DBObject ref , DBObject fields , int numToSkip , int batchSize, int limit , int options )
throws MongoException {
if ( ref == null )
ref = new BasicDBObject();
// 輸出跟蹤信息
if ( willTrace() ) trace( "find: " + _fullNameSpace + " " + JSON.serialize( ref ) );
// 構造 OutMessage
OutMessage query = OutMessage.query( _mongo , options , _fullNameSpace , numToSkip , chooseBatchSize(batchSize, limit, 0) , ref , fields );
// 調用 DBTCPConnector 的 call 方法獲得查詢結果
Response res = _connector.call( _db , this , query , null , 2 );
// 沒有結果
if ( res.size() == 0 )
return null;
// 檢查錯誤
if ( res.size() == 1 ){
BSONObject foo = res.get(0);
MongoException e = MongoException.parse( foo );
if ( e != null && ! _name.equals( "$cmd" ) )
throw e;
}
// 返回結果
return new Result( this , res , batchSize, limit , options );
}
借助 DBApiLayer.Result 遍歷結果
DBApiLayer.MyCollection._find 方法返回的是 Result 對象,它實現了 Iterator 接口,可以用于遍歷。
next 方法和 hasNext 中都用到了 _advance 方法
// 獲取下一條記錄
public DBObject next(){
// 當前 cursor 有下一條記錄,直接返回
if ( _cur.hasNext() ) {
return _cur.next();
}
// 沒有結果,拋異常
if ( ! _curResult.hasGetMore( _options ) )
throw new RuntimeException( "no more" );
// 有結果,但不在當前 cursor 中,取下一批數據
_advance();
// 遞歸調用
return next();
}
// 是否包含下一條記錄
public boolean hasNext(){
// 循環檢查
while ( true ){
// 當前 cursor 有下一條記錄,直接返回 true
if ( _cur.hasNext() )
return true;
// 沒有結果,返回 false
if ( ! _curResult.hasGetMore( _options ) )
return false;
// 有結果,但不在當前 cursor 中,取下一批數據
_advance();
}
}
// 進行到下一條記錄
private void _advance(){
if ( _curResult.cursor() <= 0 )
throw new RuntimeException( "can't advance a cursor <= 0" );
OutMessage m = new OutMessage( _mongo , 2005 );
// 以 0 作為交互開始的信號
m.writeInt( 0 );
// 輸出完整的 namespace
m.writeCString( _collection._fullNameSpace );
// 輸出數據大小
m.writeInt( chooseBatchSize(_batchSize, _limit, _numFetched) );
// 輸出當前 cusor 的位置
m.writeLong( _curResult.cursor() );
// 借助 DBTCPConnector 執行讀取操作
Response res = _connector.call( DBApiLayer.this , _collection , m , _host );
// 讀取下一條
_numGetMores++;
// 初始化
init( res );
}