Mongodb總結5-通過裝飾模式,用Mongodb解決Hbase的不穩定問題

小雷FansUnion發表於2015-10-14
最近繼續學習Mongodb的根本原因,是為了解決今天的問題。
專案中用到了Hbase,生產環境伺服器用了3臺,但是不夠穩定,每2天左右,就連不上了。
重啟就好了,當然,這是一個歷史遺留問題。
我在想,是不是連線沒有關閉,每次都是建立新的連線?
瞅瞅Java訪問Hbase的程式碼,都close了額。


原來的Hbase,用Java訪問,有add/update、get、getList3個介面。
現在要加上Mongodb儲存,儘可能保證Hbase和Mongodb資料同步。
優先使用Mongodb中的資料,其次才使用HBase中的資料。


今後有可能不再使用Hbase。


在專案剛剛啟動的時候,需要同步HBase中的資料到Mongodb。
簡化程式碼如下
public class ProjectDetailClient {
private ProjectDetailHbaseClient hbase = new ProjectDetailHbaseClient();
private ProjectDetailMongodbClient mongodb = new ProjectDetailMongodbClient();

// 2個都增加
public void add(ProjectDetail projectDetail) {
}


可以這麼理解,原來直接使用ProjectDetailHbaseClient,方法名稱都一樣。
後臺增加了ProjectDetailMongodbClient,方法的實現也一樣,可以看作是一套介面的2套實現。
ProjectDetailClient的add等具體方法中,會處理2個介面的呼叫、資料同步等邏輯問題。


完整程式碼如下

package com.hanhai.zrb.api.mongodb;

import java.util.List;

import org.apache.log4j.Logger;

import casia.isiteam.zrb.hbase.client.ProjectDetailHbaseClient;

import com.hanhai.zrb.model.project.ProjectDetail;

public class ProjectDetailClient {
	private ProjectDetailHbaseClient hbase = new ProjectDetailHbaseClient();
	private ProjectDetailMongodbClient mongodb = new ProjectDetailMongodbClient();
	private Logger log = Logger.getLogger(getClass());

	// 2個都增加
	public void add(ProjectDetail projectDetail) {
		log.info("Add ProjectDetail for hbase.");
		hbase.insertProjectDetail(projectDetail);
		log.info("Add ProjectDetail for mongodb.");
		mongodb.add(projectDetail);
	}

	// 2個都更新
	public void update(ProjectDetail projectDetail) {
		if (projectDetail.getId() == null) {
			log.error("ProjectDetail is is null,Cantnot update~");
			return;
		}
		Long id = projectDetail.getId();
	
		ProjectDetail one = mongodb.get(id);
		// Mongodb,如果存在,更新
		if (one != null) {
			log.info("Update ProjectDetail,Mongodb exists,id="+id);
			mongodb.update(projectDetail);
		}
		// 不存在,就增加
		else {
			log.info("Update ProjectDetail,Mongodb not exists,id="+id);
			mongodb.add(projectDetail);
		}
		
		// hbase增加和更新是同一個介面
		log.info("Update ProjectDetail for hbase,id="+id);
		hbase.insertProjectDetail(projectDetail);
	}

	// 2個都查詢,優先使用Mongodb
	public ProjectDetail get(long id) {
		ProjectDetail one = null;
		ProjectDetail hbaseOne = hbase.getProjectDetail(id);
		ProjectDetail mongodbOne = mongodb.get(id);
		if (mongodbOne != null) {
			one = mongodbOne;
			log.info("Project Detail,Mongodb exists,Use Mongodb," + one);
		} else if (hbaseOne != null) {
			one = hbaseOne;
			log.info("Project Detail,Mongodb not exists,Use Hbase," + one);
			log.info("Add Project Detail To Mongodb");
			// 同步Hbase中的資料到Mongodb
			mongodb.add(hbaseOne);
		}
		return one;
	}

	// 2個都查詢,優先使用Mongodb
	public List<ProjectDetail> getProjectInfoBasic(List<Long> idList) {
		List<ProjectDetail> list = null;
		List<ProjectDetail> hbaseList = hbase.getProjectInfoBasic(idList);
		List<ProjectDetail> mongodbList = mongodb.getProjectInfoBasic(idList);
		// 優先使用Mongodb中的,條件,Mongodb中的個數不小於hbase中的
		if (mongodbList != null) {
			int size = mongodbList.size();
			if (hbaseList == null || hbaseList.size() <= size) {
				list = mongodbList;
				log.info("ProjectDetail list,Use MongodbList,size=" + size);
			}else{
				list = hbaseList;
				log.info("ProjectDetail list,Use HbaseList,size=" + hbaseList.size()+",mongodb count "+size+" < hbase count "+hbaseList.size());
			}
		}
		// 其次使用Hbase中的,不會同步hbase中的資料到Mongodb
		else if (hbaseList != null) {
			list = hbaseList;
			log.info("ProjectDetail list,Use HbaseList,size=" + hbaseList.size());
		}
		return list;
	}
}

package com.hanhai.zrb.api.mongodb;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

import com.hanhai.zrb.model.project.ProjectDetail;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.CommandResult;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.WriteResult;

public class ProjectDetailMongodbClient {

	public static final String CON_NAME = "projectDetail";

	private Logger log = Logger.getLogger(getClass());

	public void add(ProjectDetail projectDetail) {
		DBCollection con = getCon();
		add(con, projectDetail);
	}

	private DBCollection getCon() {
		DB db = MongoUtil.db();
		DBCollection con = db.getCollection(CON_NAME);
		return con;
	}

	// 增加
	private DBCollection add(DBCollection projectDetailCollection,
			ProjectDetail projectDetail) {
		DBObject object = BeanUtil.bean2DBObject(projectDetail);
		WriteResult wr = projectDetailCollection.insert(object);
		CommandResult cr = wr.getLastError();
		log.info("Add new projectDetail,result:" + cr);
		return projectDetailCollection;
	}

	public void update(ProjectDetail projectDetail) {
		DBCollection con = getCon();
		update(con, projectDetail);
	}

	// 修改
	private void update(DBCollection collection, ProjectDetail projectDetail) {
		if (projectDetail.getId() == null) {
			log.error("Update projectDetail,must have a unique id");
			return;
		}

		BasicDBObject updateCondition = new BasicDBObject();
		updateCondition.append("id", projectDetail.getId());

		DBObject newObject = BeanUtil.bean2DBObject(projectDetail);

		DBObject updateSetValue = new BasicDBObject("$set", newObject);
		WriteResult wr = collection.update(updateCondition, updateSetValue);
		log.info("Update new projectDetail,result:" + wr);
	}

	public ProjectDetail get(long id) {
		DBCollection con = getCon();
		ProjectDetail projectDetail = findById(con, id);
		return projectDetail;
	}

	// 從集合中,根據ID查詢
	private ProjectDetail findById(DBCollection collection, Long id) {
		BasicDBObject searchProjectDetailById = new BasicDBObject();
		searchProjectDetailById.append("id", id);
		ProjectDetail projectDetailBefore = null;
		// findOne方法更簡單一些
		DBCursor cursor = collection.find(searchProjectDetailById);
		while (cursor.hasNext()) {
			DBObject articleObject = cursor.next();
			if (articleObject != null) {
				projectDetailBefore = objectToArticle(articleObject);
				String internalId = articleObject.get("_id").toString();
				projectDetailBefore.setMongoId(internalId);
			}
		}
		cursor.close();
		return projectDetailBefore;
	}

	// 物件轉換
	private ProjectDetail objectToArticle(DBObject object) {
		ProjectDetail projectDetail = new ProjectDetail();
		// 用工具方法轉換,手動轉換,需要判斷型別,比較麻煩
		projectDetail = BeanUtil.dbObject2Bean(object, projectDetail);
		return projectDetail;
	}

	public List<ProjectDetail> getProjectInfoBasic(List<Long> idList) {
		DBCollection con = getCon();
		List<ProjectDetail> list = findByIdList(con, idList);
		return list;
	}

	// 根據ID集合查詢
	private List<ProjectDetail> findByIdList(DBCollection collection,
			List<Long> idList) {
		BasicDBList values = new BasicDBList();
		values.addAll(idList);

		DBObject inQuery = new BasicDBObject("$in", values);

		DBObject con = new BasicDBObject();
		con.put("id", inQuery);
		DBCursor cursorIdArray = collection.find(con);

		List<ProjectDetail> projectDetailList = new ArrayList<ProjectDetail>();
		while (cursorIdArray.hasNext()) {
			DBObject articleObject = cursorIdArray.next();
			ProjectDetail projectDetail = new ProjectDetail();
			BeanUtil.dbObject2Bean(articleObject, projectDetail);
			String mongoId = articleObject.get("_id").toString();
			projectDetail.setMongoId(mongoId);

			projectDetailList.add(projectDetail);
		}
		return projectDetailList;
	}

}



ProjectDetailHbaseClient程式碼較為複雜,和ProjectDetailMongodbClient類似,不再貼了。

相關文章