Java遊戲服務器成長之路——你好,Mongo

關於mongo的思考

第一階段的弱聯網遊戲已基本完成,截至今天下午,測試也基本差很少了,前端還有一些小bug須要優化,接下來會接入小米,360,百度,騰訊等平臺,而後推廣一波,年前公司還能賺一筆,而我,也即將準備作下一款SLG。上一次,我第一次嘗試了Netty,而且也着實感覺到了Nio的魅力,Netty的魅力,在作的過程當中也學到了不少有用的東西,這一次,在數據持久化方面,我思考了好久,我愈加的以爲,我即將作的這款遊戲的數據用nosql來存儲更合適,甚至是以前作的那款弱聯網遊戲的存儲,我也認爲彷佛應該使用nosql來作存儲,由於遊戲數據的擴展性太強了,也不須要傳統關係型數據庫那些複雜的約束,彷佛是高性能的mongo更適合這類數據的存儲,以前由於項目比較急,沒敢在數據庫這塊作嘗試,而此次,我準備嘗試使用Mongo作數據層的持久化,之前作Web開發的時候,項目中用過Mongo,可是當時對它瞭解並很少,最多瞭解到它是一種文檔型數據庫,和傳統數據庫有較大區別,但我並無太多的瞭解,而當我開始作遊戲以後,卻愈來愈以爲這種Nosql數據庫彷佛更加適合遊戲數據存儲的需求。最終我仍是準備使用mongo來作數據持久化,而後開始了個人mongo之旅,心中不禁說了一句——你好,mongo!javascript

初識mongo

衆多nosql數據庫中,我爲何要用mongo呢?實際上,我還會用到memcache和redis,memcached用來作緩存,memcache的緩存性能相信你們也清楚,用它來配合mongo來作緩存再適合不過了,把玩家完整的遊戲數據都放在緩存中,讀取所有數據直接讀取緩存(具體哪些數據緩存到時候看狀況而定),而使用redis,主要是看中它多樣的數據類型和數據本地化的功能,而且redis的性能也沒必要memcache差多少,而mongo,更是一種高性能的文檔型數據庫,不瞭解的同窗能夠去官網逛逛,mongo的官網地址:http://www.mongo.org Mongo主要特下以下:前端

  1. 文檔存儲:首先就是存儲方式——文檔存儲,這一特性某種程度上決定了mongo數據庫的性能,mongo中得數據以bson形式存儲(二進制的json),屬性中能夠再嵌套bson,很是靈活,對於一個層級式的數據結構來講,若是要將這樣的數據使用扁平式的,表狀的結構來保存數據,這不管是在查詢仍是獲取數據時都十分困難。好比說一個玩家數據,有角色名,有性別,有等級,還有揹包,揹包中物品,物品還有屬性,若是按照傳統數據庫的思惟,可能會有一個玩家基礎屬性表,一個揹包表,這樣查詢起來就要聯合兩張表進行查詢,而在mongo中,這就是一條數據,一個玩家一條數據,直接一個玩家id,就包括了角色名,性別等,還包括了揹包,揹包中再嵌套一個bson來存儲揹包中得物品,物品再繼續嵌套其屬性,就這樣,一個id就能查出這個玩家全部的數據,並且mongo的查詢性能也是至關高效的。MongoDB javascript shell是一個基於javascript的解釋器,在mongo中,你還可使用js來操做mongo。
  2. 可擴展性:這一點大概是最適合遊戲開發中得特性之一,遊戲數據是多變,可能今天玩家數據結構中要加一個屬性,明天玩家數據結構中又要去掉一個屬性,對於關係型數據庫來講,面對千行數據,可能你就發愁了,而mongo不用擔憂,它能夠很容易的橫向擴展
  3. 易於查詢:這和第一點有很大關係,MongoDB以文檔的形式存儲數據,不支持事務和錶鏈接。所以查詢的編寫、理解和優化都容易得多。簡單查詢設計思路不一樣於SQL模式,嵌入文檔在特定的環境下可獲得更好的查詢。遊戲後端處理是要求效率的,這一點點大大提高了mongo在遊戲後端中可用性。
  4. 安全性:因爲MongoDB客戶端生成的查詢爲BSON對象,而不是能夠被解析的字符串,因此可下降受到SQL注入的攻擊的危險。不一樣於常見的sql語句,普通的sql攻擊天然對bson無效。

僅憑以上4點,我認爲,像我作的這種數據類型複雜多變的遊戲數據用mongo來存儲再合適不過了。固然mongo還有更多的優勢如複製和故障恢復,支持徹底索引等。java

瞭解API

mongo自己是由C++編寫的,可它卻也支持不少語言,固然,最重要的是,它有提供Java api,如下是mongo java api官方文檔:http://api.mongodb.org/java/2.11.2/ 固然,既然有官方api,那就必定有人封裝了更方便更好用的框架出來,像morphia,就是一款相似於關係型數據庫ORM的Hibernate同樣,方便易用,另外,spring也提供了mongo的封裝,有興趣的均可以去了解一下,畢竟每一個人有本身的習慣,本身喜歡的纔是最好的。使用官方提供的java api,操做mongo也是很是的方便,舉例,好比如下保存對象的方法:redis

          //第一:實例化mongo對象,鏈接mongodb服務器  包含全部的數據庫  
          //默認構造方法,默認是鏈接本機,端口號,默認是27017  
          //至關於Mongo mongo =new Mongo("localhost",27017)  
          Mongo mongo =new Mongo();  
           
          //第二:鏈接具體的數據庫  
          //其中參數是具體數據庫的名稱,若服務器中不存在,會自動建立  
          DB db=mongo.getDB("myMongo");  
           
          //第三:操做具體的表  
         //在mongodb中沒有表的概念,而是指集合  
          //其中參數是數據庫中表,若不存在,會自動建立  
          DBCollection collection=db.getCollection("user");  
           
          //添加操做  
          //在mongodb中沒有行的概念,而是指文檔  
          BasicDBObject document=new BasicDBObject();  
           
          document.put("id", 1);  
          document.put("name", "小明");  
          //而後保存到集合中  
          //collection.insert(document);  
   
          //固然我也能夠保存這樣的json串  
          /*  {  
               "id":1,  
               "name","小明",  
               "address":  
               {  
               "city":"beijing",  
               "code":"065000"  
               }  
          }*/  
          //實現上述json串思路以下:  
          //第一種:相似xml時,不斷添加  
          BasicDBObject addressDocument=new BasicDBObject();  
          addressDocument.put("city", "beijing");  
          addressDocument.put("code", "065000");  
          document.put("address", addressDocument);  
          //而後保存數據庫中  
          collection.insert(document);  
           
          //第二種:直接把json存到數據庫中  
          /* String jsonTest="{'id':1,'name':'小明',"+  
                   "'address':{'city':'beijing','code':'065000'}"+  
                    "}";  
         DBObject dbobjct=(DBObject)JSON.parse(jsonTest);  
         collection.insert(dbobjct);*/  

其他方法我就不贅述了,想了解的能夠查官方文檔。spring

使用mongo

既然決定使用mongo,那就要着手開始寫工具類,按照官方文檔,我寫了MongoUtil和DBObjectUtil兩個工具類,MongoUtil負責數據庫的鏈接和操做,DBObjectUtil則是Mongo中的操做對象DBObject與Javabean之間的相互轉換。首先,我要在個人maven的pom.xml文件中依賴mongo的jar包sql

<dependency>
  <groupId>org.mongodb</groupId>
  <artifactId>mongo-java-driver</artifactId>
  <version>2.11.2</version>
</dependency>

而後是個人MongoUtil類,其中簡單作了數據庫的鏈接管理,MC是Memcache緩存,這部分代碼就不貼出來了,上篇文章已貼出過Memcache部分代碼:mongodb

/**
 * @ClassName: MongoUtil
 * @Description: mongo
 * @author 何金成
 * @date 2016年1月19日 下午3:35:25
 * 
 */
public class MongoUtil {

 private MongoClient mongo = null;
 private DB db = null;
 private static Logger logger = LoggerFactory.getLogger(MongoUtil.class);
 private static final Map<String, MongoUtil> instances = new ConcurrentHashMap<String, MongoUtil>();
 private static final String CONF_PATH = "/spring-mongodb/mongodb.properties";
 public static final String DB_ID = "id";// DB中id字段名

 /**
  * 實例化
  * 
  * @return MongoDBManager對象
  */
 static {
  getInstance("db");// 初始化默認的MongoDB數據庫
 }

 public static MongoUtil getInstance() {
  return getInstance("db");// 配置文件默認數據庫前綴爲db
 }

 public static MongoUtil getInstance(String dbName) {
  MongoUtil mongoMgr = instances.get(dbName);
  if (mongoMgr == null) {
   mongoMgr = buildInstance(dbName);
   if (mongoMgr == null) {
    return null;
   }
   instances.put(dbName, mongoMgr);
  }
  return mongoMgr;
 }

 private static synchronized MongoUtil buildInstance(String dbName) {
  MongoUtil mongoMgr = new MongoUtil();
  try {
   mongoMgr.mongo = new MongoClient(getServerAddress(dbName),
     getMongoCredential(dbName), getDBOptions(dbName));
   mongoMgr.db = mongoMgr.mongo.getDB(getProperty(CONF_PATH, dbName
     + ".database"));
   logger.info("connect to MongoDB success!");
   boolean flag = mongoMgr.db.authenticate(
     getProperty(CONF_PATH, dbName + ".username"),
     getProperty(CONF_PATH, dbName + ".password").toCharArray());
   if (!flag) {
    logger.error("MongoDB auth failed");
    return null;
   }
  } catch (Exception e) {
   logger.info("Can't connect " + dbName + " MongoDB! {}", e);
   return null;
  }
  return mongoMgr;
 }

 /**
  * 根據properties文件的key獲取value
  * 
  * @param filePath
  *            properties文件路徑
  * @param key
  *            屬性key
  * @return 屬性value
  */
 private static String getProperty(String filePath, String key) {
  Properties props = new Properties();
  try {
   InputStream in = MongoUtil.class.getResourceAsStream(filePath);
   props.load(in);
   String value = props.getProperty(key);
   return value;
  } catch (Exception e) {
   logger.info("load mongo properties exception {}", e);
   System.exit(0);
   return null;
  }
 }

 /**
  * 獲取集合(表)
  * 
  * @param collection
  */
 public DBCollection getCollection(String collection) {
  DBCollection collect = db.getCollection(collection);
  return collect;
 }

 /**
  * 插入
  * 
  * @param collection
  * @param o
  */
 public void insert(String collection, DBObject o) {
  getCollection(collection).insert(o);
  // 添加到MC控制
  MC.add(o, o.get(DB_ID));
 }

 /**
  * 批量插入
  * 
  * @param collection
  * @param list
  */
 public void insertBatch(String collection, List<DBObject> list) {
  if (list == null || list.isEmpty()) {
   return;
  }
  getCollection(collection).insert(list);
  // 批量插入MC
  for (DBObject o : list) {
   MC.add(o, o.get(DB_ID));
  }
 }

 /**
  * 刪除
  * 
  * @param collection
  * @param q
  *            查詢條件
  */
 public List<DBObject> delete(String collection, DBObject q) {
  getCollection(collection).remove(q);
  List<DBObject> list = find(collection, q);
  // MC中刪除
  for (DBObject tmp : list) {
   DBObject dbObject = MC.<DBObject> get(DBObject.class,
     (Long) tmp.get(DB_ID));
   if (null != dbObject) {
    MC.delete(DBObject.class, (Long) dbObject.get(DB_ID));
   }
  }
  return list;
 }

 /**
  * 批量刪除
  * 
  * @param collection
  * @param list
  *            刪除條件列表
  */
 public void deleteBatch(String collection, List<DBObject> list) {
  if (list == null || list.isEmpty()) {
   return;
  }
  for (int i = 0; i < list.size(); i++) {
   // 批量條件刪除
   delete(collection, list.get(i));
  }
 }

 /**
  * 計算集合總條數
  * 
  * @param collection
  */
 public int getCount(String collection) {
  int count = (int) getCollection(collection).find().count();
  return count;
 }

 /**
  * 計算知足條件條數
  * 
  * @param collection
  * @param q
  *            查詢條件
  */

 public long getCount(String collection, DBObject q) {
  return getCollection(collection).getCount(q);
 }

 /**
  * 更新
  * 
  * @param collection
  * @param q
  *            查詢條件
  * @param setFields
  *            更新對象
  * @return List<DBObject> 更新後的對象列表
  */
 public List<DBObject> update(String collection, DBObject q,
   DBObject setFields) {
  getCollection(collection).updateMulti(q,
    new BasicDBObject("$set", setFields));
  List<DBObject> list = find(collection, q);
  // 遍歷
  for (DBObject dbObject : list) {
   // MC 中修改
   DBObject tmp = MC.<DBObject> get(DBObject.class,
     (Long) dbObject.get(DB_ID));
   if (null != tmp) {
    MC.update(dbObject, (Long) tmp.get(DB_ID));
   }
  }
  return list;
 }

 /**
  * 查找集合全部對象
  * 
  * @param collection
  */
 public List<DBObject> findAll(String collection) {
  List<DBObject> list = getCollection(collection).find().toArray();
  return list;
 }

 /**
  * 按順序查找集合全部對象
  * 
  * @param collection
  *            數據集
  * @param orderBy
  *            排序
  */
 public List<DBObject> findAll(String collection, DBObject orderBy) {
  return getCollection(collection).find().sort(orderBy).toArray();
 }

 /**
  * 查找(返回一個對象)
  * 
  * @param collection
  * @param q
  *            查詢條件
  */
 public DBObject findOne(String collection, DBObject q) {
  return findOne(collection, q, null);
 }

 /**
  * 查找(返回一個對象)
  * 
  * @param collection
  * @param q
  *            查詢條件
  * @param fileds
  *            返回字段
  */
 public DBObject findOne(String collection, DBObject q, DBObject fields) {
  if (q.containsField(DB_ID)) {// 若是根據id來查詢,先從緩存取數據
   DBObject tmp = MC.<DBObject> get(DBObject.class,
     (Long) q.get(DB_ID));
   if (tmp != null) {// 緩存沒有數據,從數據庫取
    if (fields != null) {// 留下須要返回的字段
     for (String key : tmp.keySet()) {
      if (!fields.containsField(key)) {
       tmp.removeField(key);
      }
     }
    }
    return tmp;
   }
  }
  return fields == null ? getCollection(collection).findOne(q)
    : getCollection(collection).findOne(q, fields);
 }

 /**
  * 查找返回特定字段(返回一個List<DBObject>)
  * 
  * @param collection
  * @param q
  *            查詢條件
  * @param fileds
  *            返回字段
  */
 public List<DBObject> findLess(String collection, DBObject q,
   DBObject fileds) {
  DBCursor c = getCollection(collection).find(q, fileds);
  if (c != null)
   return c.toArray();
  else
   return null;
 }

 /**
  * 查找返回特定字段(返回一個List<DBObject>)
  * 
  * @param collection
  * @param q
  *            查詢條件
  * @param fileds
  *            返回字段
  * @param orderBy
  *            排序
  */
 public List<DBObject> findLess(String collection, DBObject q,
   DBObject fileds, DBObject orderBy) {
  DBCursor c = getCollection(collection).find(q, fileds).sort(orderBy);
  if (c != null)
   return c.toArray();
  else
   return null;
 }

 /**
  * 分頁查找集合對象,返回特定字段
  * 
  * @param collection
  * @param q
  *            查詢條件
  * @param fileds
  *            返回字段
  * @pageNo 第n頁
  * @perPageCount 每頁記錄數
  */
 public List<DBObject> findLess(String collection, DBObject q,
   DBObject fileds, int pageNo, int perPageCount) {
  return getCollection(collection).find(q, fileds)
    .skip((pageNo - 1) * perPageCount).limit(perPageCount)
    .toArray();
 }

 /**
  * 按順序分頁查找集合對象,返回特定字段
  * 
  * @param collection
  *            集合
  * @param q
  *            查詢條件
  * @param fileds
  *            返回字段
  * @param orderBy
  *            排序
  * @param pageNo
  *            第n頁
  * @param perPageCount
  *            每頁記錄數
  */
 public List<DBObject> findLess(String collection, DBObject q,
   DBObject fileds, DBObject orderBy, int pageNo, int perPageCount) {
  return getCollection(collection).find(q, fileds).sort(orderBy)
    .skip((pageNo - 1) * perPageCount).limit(perPageCount)
    .toArray();
 }

 /**
  * 查找(返回一個List<DBObject>)
  * 
  * @param collection
  * @param q
  *            查詢條件
  */
 public List<DBObject> find(String collection, DBObject q) {
  DBCursor c = getCollection(collection).find(q);
  if (c != null)
   return c.toArray();
  else
   return null;
 }

 /**
  * 按順序查找(返回一個List<DBObject>)
  * 
  * @param collection
  * @param q
  *            查詢條件
  * @param orderBy
  *            排序
  */
 public List<DBObject> find(String collection, DBObject q, DBObject orderBy) {
  DBCursor c = getCollection(collection).find(q).sort(orderBy);
  if (c != null)
   return c.toArray();
  else
   return null;
 }

 /**
  * 分頁查找集合對象
  * 
  * @param collection
  * @param q
  *            查詢條件
  * @pageNo 第n頁
  * @perPageCount 每頁記錄數
  */
 public List<DBObject> find(String collection, DBObject q, int pageNo,
   int perPageCount) {
  return getCollection(collection).find(q)
    .skip((pageNo - 1) * perPageCount).limit(perPageCount)
    .toArray();
 }

 /**
  * 按順序分頁查找集合對象
  * 
  * @param collection
  *            集合
  * @param q
  *            查詢條件
  * @param orderBy
  *            排序
  * @param pageNo
  *            第n頁
  * @param perPageCount
  *            每頁記錄數
  */
 public List<DBObject> find(String collection, DBObject q, DBObject orderBy,
   int pageNo, int perPageCount) {
  return getCollection(collection).find(q).sort(orderBy)
    .skip((pageNo - 1) * perPageCount).limit(perPageCount)
    .toArray();
 }

 /**
  * distinct操做
  * 
  * @param collection
  *            集合
  * @param field
  *            distinct字段名稱
  */
 public Object[] distinct(String collection, String field) {
  return getCollection(collection).distinct(field).toArray();
 }

 /**
  * distinct操做
  * 
  * @param collection
  *            集合
  * @param field
  *            distinct字段名稱
  * @param q
  *            查詢條件
  */
 public Object[] distinct(String collection, String field, DBObject q) {
  return getCollection(collection).distinct(field, q).toArray();
 }

 /**
  * group分組查詢操做,返回結果少於10,000keys時可使用
  * 
  * @param collection
  *            集合
  * @param key
  *            分組查詢字段
  * @param q
  *            查詢條件
  * @param reduce
  *            reduce Javascript函數,如:function(obj,
  *            out){out.count++;out.csum=obj.c;}
  * @param finalize
  *            reduce
  *            function返回結果處理Javascript函數,如:function(out){out.avg=out.csum
  *            /out.count;}
  */
 public BasicDBList group(String collection, DBObject key, DBObject q,
   DBObject initial, String reduce, String finalize) {
  return ((BasicDBList) getCollection(collection).group(key, q, initial,
    reduce, finalize));
 }

 /**
  * group分組查詢操做,返回結果大於10,000keys時可使用
  * 
  * @param collection
  *            集合
  * @param map
  *            映射javascript函數字符串,如:function(){ for(var key in this) {
  *            emit(key,{count:1}) } }
  * @param reduce
  *            reduce Javascript函數字符串,如:function(key,emits){ total=0; for(var
  *            i in emits){ total+=emits[i].count; } return {count:total}; }
  * @param q
  *            分組查詢條件
  * @param orderBy
  *            分組查詢排序
  */
 public Iterable<DBObject> mapReduce(String collection, String map,
   String reduce, DBObject q, DBObject orderBy) {
  // DBCollection coll = db.getCollection(collection);
  // MapReduceCommand cmd = new MapReduceCommand(coll, map, reduce, null,
  // MapReduceCommand.OutputType.INLINE, q);
  // return coll.mapReduce(cmd).results();
  MapReduceOutput out = getCollection(collection).mapReduce(map, reduce,
    null, q);
  return out.getOutputCollection().find().sort(orderBy).toArray();
 }

 /**
  * group分組分頁查詢操做,返回結果大於10,000keys時可使用
  * 
  * @param collection
  *            集合
  * @param map
  *            映射javascript函數字符串,如:function(){ for(var key in this) {
  *            emit(key,{count:1}) } }
  * @param reduce
  *            reduce Javascript函數字符串,如:function(key,emits){ total=0; for(var
  *            i in emits){ total+=emits[i].count; } return {count:total}; }
  * @param q
  *            分組查詢條件
  * @param orderBy
  *            分組查詢排序
  * @param pageNo
  *            第n頁
  * @param perPageCount
  *            每頁記錄數
  */
 public List<DBObject> mapReduce(String collection, String map,
   String reduce, DBObject q, DBObject orderBy, int pageNo,
   int perPageCount) {
  MapReduceOutput out = getCollection(collection).mapReduce(map, reduce,
    null, q);
  return out.getOutputCollection().find().sort(orderBy)
    .skip((pageNo - 1) * perPageCount).limit(perPageCount)
    .toArray();
 }

 /**
  * group分組查詢操做,返回結果大於10,000keys時可使用
  * 
  * @param collection
  *            集合
  * @param map
  *            映射javascript函數字符串,如:function(){ for(var key in this) {
  *            emit(key,{count:1}) } }
  * @param reduce
  *            reduce Javascript函數字符串,如:function(key,emits){ total=0; for(var
  *            i in emits){ total+=emits[i].count; } return {count:total}; }
  * @param outputCollectionName
  *            輸出結果表名稱
  * @param q
  *            分組查詢條件
  * @param orderBy
  *            分組查詢排序
  */
 public List<DBObject> mapReduce(String collection, String map,
   String reduce, String outputCollectionName, DBObject q,
   DBObject orderBy) {
  if (!db.collectionExists(outputCollectionName)) {
   getCollection(collection).mapReduce(map, reduce,
     outputCollectionName, q);
  }
  return getCollection(outputCollectionName)
    .find(null, new BasicDBObject("_id", false)).sort(orderBy)
    .toArray();
 }

 /**
  * group分組分頁查詢操做,返回結果大於10,000keys時可使用
  * 
  * @param collection
  *            集合
  * @param map
  *            映射javascript函數字符串,如:function(){ for(var key in this) {
  *            emit(key,{count:1}) } }
  * @param reduce
  *            reduce Javascript函數字符串,如:function(key,emits){ total=0; for(var
  *            i in emits){ total+=emits[i].count; } return {count:total}; }
  * @param outputCollectionName
  *            輸出結果表名稱
  * @param q
  *            分組查詢條件
  * @param orderBy
  *            分組查詢排序
  * @param pageNo
  *            第n頁
  * @param perPageCount
  *            每頁記錄數
  */
 public List<DBObject> mapReduce(String collection, String map,
   String reduce, String outputCollectionName, DBObject q,
   DBObject orderBy, int pageNo, int perPageCount) {
  if (!db.collectionExists(outputCollectionName)) {
   getCollection(collection).mapReduce(map, reduce,
     outputCollectionName, q);
  }
  return getCollection(outputCollectionName)
    .find(null, new BasicDBObject("_id", false)).sort(orderBy)
    .skip((pageNo - 1) * perPageCount).limit(perPageCount)
    .toArray();
 }

 /**
  * @Title: getServerAddress
  * @Description: 獲取數據庫服務器列表
  * @param dbName
  * @return
  * @throws UnknownHostException
  * @return List<ServerAddress>
  * @throws
  */
 private static List<ServerAddress> getServerAddress(String dbName)
   throws UnknownHostException {
  List<ServerAddress> list = new ArrayList<ServerAddress>();
  String hosts = getProperty(CONF_PATH, dbName + ".host");
  for (String host : hosts.split("&")) {
   String ip = host.split(":")[0];
   String port = host.split(":")[1];
   list.add(new ServerAddress(ip, Integer.parseInt(port)));
  }
  return list;
 }

 /**
  * @Title: getMongoCredential
  * @Description: 獲取數據庫安全驗證信息
  * @param dbName
  * @return
  * @return List<MongoCredential>
  * @throws
  */
 private static List<MongoCredential> getMongoCredential(String dbName) {
  String username = getProperty(CONF_PATH, dbName + ".username");
  String password = getProperty(CONF_PATH, dbName + ".password");
  String database = getProperty(CONF_PATH, dbName + ".database");
  MongoCredential credentials = MongoCredential.createMongoCRCredential(
    username, database, password.toCharArray());
  List<MongoCredential> credentialsList = new ArrayList<MongoCredential>();
  credentialsList.add(credentials);
  return credentialsList;
 }

 /**
  * @Title: getDBOptions
  * @Description: 獲取數據參數設置
  * @return
  * @return MongoClientOptions
  * @throws
  */
 private static MongoClientOptions getDBOptions(String dbName) {
  MongoClientOptions.Builder build = new MongoClientOptions.Builder();
  build.connectionsPerHost(Integer.parseInt(getProperty(CONF_PATH, dbName
    + ".connectionsPerHost"))); // 與目標數據庫可以創建的最大connection數量爲50
  build.threadsAllowedToBlockForConnectionMultiplier(Integer
    .parseInt(getProperty(CONF_PATH, dbName
      + ".threadsAllowedToBlockForConnectionMultiplier"))); // 若是當前全部的connection都在使用中,則每一個connection上能夠有50個線程排隊等待
  build.maxWaitTime(Integer.parseInt(getProperty(CONF_PATH, dbName
    + ".maxWaitTime")));
  build.connectTimeout(Integer.parseInt(getProperty(CONF_PATH, dbName
    + ".connectTimeout")));
  MongoClientOptions myOptions = build.build();
  return myOptions;
 }

 public static void main(String[] args) {
  try {
   // getInstance().insert(
   // "user",
   // new BasicDBObject().append("name", "admin3")
   // .append("type", "2").append("score", 70)
   // .append("level", 2)
   // .append("inputTime", new Date().getTime()));
   // getInstance().update("user",
   // new BasicDBObject().append("status", 1),
   // new BasicDBObject().append("status", 2));
   // === group start =============
   // StringBuilder sb = new StringBuilder(100);
   // sb.append("function(obj, out){out.count++;out.").append("scoreSum")
   // .append("+=obj.").append("score").append(";out.")
   // .append("levelSum").append("+=obj.").append("level")
   // .append('}');
   // String reduce = sb.toString();
   // BasicDBList list = getInstance().group(
   // "user",
   // new BasicDBObject("type", true),
   // new BasicDBObject(),
   // new BasicDBObject().append("count", 0)
   // .append("scoreSum", 0).append("levelSum", 0)
   // .append("levelAvg", (Double) 0.0), reduce,
   // "function(out){ out.levelAvg = out.levelSum / out.count }");
   // for (Object o : list) {
   // DBObject obj = (DBObject) o;
   // System.out.println(obj);
   // }
   // ======= group end=========
   // === mapreduce start =============
   // Iterable<DBObject> list2 = getInstance()
   // .mapReduce(
   // "user",
   // "function(){emit( {type:this.type}, {score:this.score, level:this.level} );}",
   // "function(key,values){var result={score:0,level:0};var count = 0;values.forEach(function(value){result.score += value.score;result.level += value.level;count++});result.level = result.level / count;return result;}",
   // new BasicDBObject(), new BasicDBObject("score", 1));
   // for (DBObject o : list2) {
   // System.out.println(o);
   // }

   // List<DBObject> list3 = getInstance().mapReduce("user",
   // "function(){emit({type:this.type},{type:this.type,score:this.score,level:this.level});}",
   // "function(key,values){var result={type:key.type,score:0,level:0};var count=0;values.forEach(function(value){result.score+=value.score;result.level+=value.level;count++});result.level=result.level/count;return result;}",
   // "group_temp_user",
   // new BasicDBObject(),
   // new BasicDBObject("score",1));
   // for (DBObject o : list3) {
   // System.out.println(o);
   // }
   // ======= mapreduce end=========
   // System.out.print(getInstance().findAll("user"));
   // System.out.print(getInstance().find(
   // "user",
   // new BasicDBObject("inputTime", new BasicDBObject("$gt",
   // 1348020002890L)),
   // new BasicDBObject().append("_id", "-1"), 1, 2));
   // getInstance().delete("user", new BasicDBObject());
  } catch (Exception e) {
   System.out.println(e.getMessage());
  }
 }
}

如下是mongo的鏈接配置properties文件shell

#ip和端口,多個主機用&相連
db.host=127.0.0.1:27017
#數據庫名字
db.database=war
#用戶名
db.username=root
#密碼
db.password=123456
#每一個主機的最大鏈接數
db.connectionsPerHost=50
#線程容許最大等待鏈接數
db.threadsAllowedToBlockForConnectionMultiplier=50
#鏈接超時時間1分鐘
db.connectTimeout=60000
#一個線程訪問數據庫的時候,在成功獲取到一個可用數據庫鏈接以前的最長等待時間爲2分鐘
#這裏比較危險,若是超過maxWaitTime都沒有獲取到這個鏈接的話,該線程就會拋出Exception
#故這裏設置的maxWaitTime應該足夠大,以避免因爲排隊線程過多形成的數據庫訪問失敗
db.maxWaitTime=120000

DBObject和Javabean之間的轉換就容易多了,能夠經過json爲中介來轉換。數據庫

public class DBObjectUtil {

 /**
  * 把實體bean對象轉換成DBObject
  * 
  * @param bean
  * @return
  * @throws IllegalArgumentException
  * @throws IllegalAccessException
  */
 public static <T> DBObject bean2DBObject(T bean) {
  if (bean == null) {
   return null;
  }
  DBObject dbObject = new BasicDBObject();
  String json = JsonUtils.objectToJson(bean);
  dbObject = (DBObject) JSON.parse(json);
  return dbObject;
 }

 /**
  * 把DBObject轉換成bean對象
  * 
  * @param dbObject
  * @param bean
  * @return
  * @throws IllegalAccessException
  * @throws InvocationTargetException
  * @throws NoSuchMethodException
  */
 @SuppressWarnings("unchecked")
 public static <T> T dbObject2Bean(DBObject dbObject, T bean) {
  if (bean == null) {
   return null;
  }
  String json = JSON.serialize(dbObject);
  bean = (T) JsonUtils.jsonToBean(json, bean.getClass());
  return bean;
 }
}

至此,mongo搭建基本完成,更多關於mongo的探索,仍是要在實踐中完成,實踐是檢驗真理的惟一標準,nosql現在煊赫一時,但咱們也要保持理性的態度看待問題,傳統數據庫和nosql究竟誰更勝一籌,不妨咱們都動手試一試,是騾子是馬,都拉出來溜溜!以上代碼可直接用過工具類,歡迎交流探討!json

相關文章
相關標籤/搜索