关于mongo的思考

第一阶段的弱联网游戏已基本完成,截至今天下午,测试也基本差不多了,前端还有一些小bug需要优化,接下来会接入小米,360,百度,腾讯等平台,然后推广一波,年前公司还能赚一笔,而我,也即将准备做下一款SLG。上一次,我第一次尝试了Netty,并且也着实感受到了Nio的魅力,Netty的魅力,在做的过程中也学到了很多有用的东西,这一次,在数据持久化方面,我思考了很久,我越发的觉得,我即将做的这款游戏的数据用nosql来存储更合适,甚至是之前做的那款弱联网游戏的存储,我也认为似乎应该使用nosql来做存储,因为游戏数据的扩展性太强了,也不需要传统关系型数据库那些复杂的约束,似乎是高性能的mongo更适合这类数据的存储,之前因为项目比较急,没敢在数据库这块做尝试,而这次,我准备尝试使用Mongo做数据层的持久化,以前做Web开发的时候,项目中用过Mongo,但是当时对它了解并不多,最多了解到它是一种文档型数据库,和传统数据库有较大区别,但我并没有太多的了解,而当我开始做游戏之后,却越来越觉得这种Nosql数据库似乎更加适合游戏数据存储的需求。最终我还是准备使用mongo来做数据持久化,然后开始了我的mongo之旅,心中不由说了一句——你好,mongo!

初识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还有更多的优点如复制和故障恢复,支持完全索引等。

了解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也是非常的方便,举例,比如以下保存对象的方法:

  1.           //第一:实例化mongo对象,连接mongodb服务器  包含所有的数据库  
  2.           //默认构造方法,默认是连接本机,端口号,默认是27017  
  3.           //相当于Mongo mongo =new Mongo("localhost",27017)  
  4.           Mongo mongo =new Mongo();  
  5.            
  6.           //第二:连接具体的数据库  
  7.           //其中参数是具体数据库的名称,若服务器中不存在,会自动创建  
  8.           DB db=mongo.getDB("myMongo");  
  9.            
  10.           //第三:操作具体的表  
  11.          //在mongodb中没有表的概念,而是指集合  
  12.           //其中参数是数据库中表,若不存在,会自动创建  
  13.           DBCollection collection=db.getCollection("user");  
  14.            
  15.           //添加操作  
  16.           //在mongodb中没有行的概念,而是指文档  
  17.           BasicDBObject document=new BasicDBObject();  
  18.            
  19.           document.put("id", 1);  
  20.           document.put("name", "小明");  
  21.           //然后保存到集合中  
  22.           //collection.insert(document);  
  23.    
  24.           //当然我也可以保存这样的json串  
  25.           /*  {  
  26.                "id":1,  
  27.                "name","小明",  
  28.                "address":  
  29.                {  
  30.                "city":"beijing",  
  31.                "code":"065000"  
  32.                }  
  33.           }*/  
  34.           //实现上述json串思路如下:  
  35.           //第一种:类似xml时,不断添加  
  36.           BasicDBObject addressDocument=new BasicDBObject();  
  37.           addressDocument.put("city", "beijing");  
  38.           addressDocument.put("code", "065000");  
  39.           document.put("address", addressDocument);  
  40.           //然后保存数据库中  
  41.           collection.insert(document);  
  42.            
  43.           //第二种:直接把json存到数据库中  
  44.           /* String jsonTest="{'id':1,'name':'小明',"+  
  45.                    "'address':{'city':'beijing','code':'065000'}"+  
  46.                     "}";  
  47.          DBObject dbobjct=(DBObject)JSON.parse(jsonTest);  
  48.          collection.insert(dbobjct);*/  

其余方法我就不赘述了,想了解的可以查官方文档。

使用mongo

既然决定使用mongo,那就要着手开始写工具类,按照官方文档,我写了MongoUtil和DBObjectUtil两个工具类,MongoUtil负责数据库的连接和操作,DBObjectUtil则是Mongo中的操作对象DBObject与Javabean之间的相互转换。首先,我要在我的maven的pom.xml文件中依赖mongo的jar包

  1. <dependency>
  2.   <groupId>org.mongodb</groupId>
  3.   <artifactId>mongo-java-driver</artifactId>
  4.   <version>2.11.2</version>
  5. </dependency>

然后是我的MongoUtil类,其中简单做了数据库的连接管理,MC是Memcache缓存,这部分代码就不贴出来了,上篇文章已贴出过Memcache部分代码:

  1. /**
  2.  * @ClassName: MongoUtil
  3.  * @Description: mongo
  4.  * @author 何金成
  5.  * @date 2016年1月19日 下午3:35:25
  6.  * 
  7.  */
  8. public class MongoUtil {
  9. private MongoClient mongo = null;
  10. private DB db = null;
  11. private static Logger logger = LoggerFactory.getLogger(MongoUtil.class);
  12. private static final Map<String, MongoUtil> instances = new ConcurrentHashMap<String, MongoUtil>();
  13. private static final String CONF_PATH = "/spring-mongodb/mongodb.properties";
  14. public static final String DB_ID = "id";// DB中id字段名
  15. /**
  16. * 实例化

  17. * @return MongoDBManager对象
  18. */
  19. static {
  20. getInstance("db");// 初始化默认的MongoDB数据库
  21. }
  22. public static MongoUtil getInstance() {
  23. return getInstance("db");// 配置文件默认数据库前缀为db
  24. }
  25. public static MongoUtil getInstance(String dbName) {
  26. MongoUtil mongoMgr = instances.get(dbName);
  27. if (mongoMgr == null) {
  28. mongoMgr = buildInstance(dbName);
  29. if (mongoMgr == null) {
  30. return null;
  31. }
  32. instances.put(dbName, mongoMgr);
  33. }
  34. return mongoMgr;
  35. }
  36. private static synchronized MongoUtil buildInstance(String dbName) {
  37. MongoUtil mongoMgr = new MongoUtil();
  38. try {
  39. mongoMgr.mongo = new MongoClient(getServerAddress(dbName),
  40. getMongoCredential(dbName), getDBOptions(dbName));
  41. mongoMgr.db = mongoMgr.mongo.getDB(getProperty(CONF_PATH, dbName
  42. + ".database"));
  43. logger.info("connect to MongoDB success!");
  44. boolean flag = mongoMgr.db.authenticate(
  45. getProperty(CONF_PATH, dbName + ".username"),
  46. getProperty(CONF_PATH, dbName + ".password").toCharArray());
  47. if (!flag) {
  48. logger.error("MongoDB auth failed");
  49. return null;
  50. }
  51. } catch (Exception e) {
  52. logger.info("Can't connect " + dbName + " MongoDB! {}", e);
  53. return null;
  54. }
  55. return mongoMgr;
  56. }
  57. /**
  58. * 根据properties文件的key获取value

  59. * @param filePath
  60. *            properties文件路径
  61. * @param key
  62. *            属性key
  63. * @return 属性value
  64. */
  65. private static String getProperty(String filePath, String key) {
  66. Properties props = new Properties();
  67. try {
  68. InputStream in = MongoUtil.class.getResourceAsStream(filePath);
  69. props.load(in);
  70. String value = props.getProperty(key);
  71. return value;
  72. } catch (Exception e) {
  73. logger.info("load mongo properties exception {}", e);
  74. System.exit(0);
  75. return null;
  76. }
  77. }
  78. /**
  79. * 获取集合(表)

  80. * @param collection
  81. */
  82. public DBCollection getCollection(String collection) {
  83. DBCollection collect = db.getCollection(collection);
  84. return collect;
  85. }
  86. /**
  87. * 插入

  88. * @param collection
  89. * @param o
  90. */
  91. public void insert(String collection, DBObject o) {
  92. getCollection(collection).insert(o);
  93. // 添加到MC控制
  94. MC.add(o, o.get(DB_ID));
  95. }
  96. /**
  97. * 批量插入

  98. * @param collection
  99. * @param list
  100. */
  101. public void insertBatch(String collection, List<DBObject> list) {
  102. if (list == null || list.isEmpty()) {
  103. return;
  104. }
  105. getCollection(collection).insert(list);
  106. // 批量插入MC
  107. for (DBObject o : list) {
  108. MC.add(o, o.get(DB_ID));
  109. }
  110. }
  111. /**
  112. * 删除

  113. * @param collection
  114. * @param q
  115. *            查询条件
  116. */
  117. public List<DBObject> delete(String collection, DBObject q) {
  118. getCollection(collection).remove(q);
  119. List<DBObject> list = find(collection, q);
  120. // MC中删除
  121. for (DBObject tmp : list) {
  122. DBObject dbObject = MC.<DBObject> get(DBObject.class,
  123. (Long) tmp.get(DB_ID));
  124. if (null != dbObject) {
  125. MC.delete(DBObject.class, (Long) dbObject.get(DB_ID));
  126. }
  127. }
  128. return list;
  129. }
  130. /**
  131. * 批量删除

  132. * @param collection
  133. * @param list
  134. *            删除条件列表
  135. */
  136. public void deleteBatch(String collection, List<DBObject> list) {
  137. if (list == null || list.isEmpty()) {
  138. return;
  139. }
  140. for (int i = 0; i < list.size(); i++) {
  141. // 批量条件删除
  142. delete(collection, list.get(i));
  143. }
  144. }
  145. /**
  146. * 计算集合总条数

  147. * @param collection
  148. */
  149. public int getCount(String collection) {
  150. int count = (int) getCollection(collection).find().count();
  151. return count;
  152. }
  153. /**
  154. * 计算满足条件条数

  155. * @param collection
  156. * @param q
  157. *            查询条件
  158. */
  159. public long getCount(String collection, DBObject q) {
  160. return getCollection(collection).getCount(q);
  161. }
  162. /**
  163. * 更新

  164. * @param collection
  165. * @param q
  166. *            查询条件
  167. * @param setFields
  168. *            更新对象
  169. * @return List<DBObject> 更新后的对象列表
  170. */
  171. public List<DBObject> update(String collection, DBObject q,
  172. DBObject setFields) {
  173. getCollection(collection).updateMulti(q,
  174. new BasicDBObject("$set", setFields));
  175. List<DBObject> list = find(collection, q);
  176. // 遍历
  177. for (DBObject dbObject : list) {
  178. // MC 中修改
  179. DBObject tmp = MC.<DBObject> get(DBObject.class,
  180. (Long) dbObject.get(DB_ID));
  181. if (null != tmp) {
  182. MC.update(dbObject, (Long) tmp.get(DB_ID));
  183. }
  184. }
  185. return list;
  186. }
  187. /**
  188. * 查找集合所有对象

  189. * @param collection
  190. */
  191. public List<DBObject> findAll(String collection) {
  192. List<DBObject> list = getCollection(collection).find().toArray();
  193. return list;
  194. }
  195. /**
  196. * 按顺序查找集合所有对象

  197. * @param collection
  198. *            数据集
  199. * @param orderBy
  200. *            排序
  201. */
  202. public List<DBObject> findAll(String collection, DBObject orderBy) {
  203. return getCollection(collection).find().sort(orderBy).toArray();
  204. }
  205. /**
  206. * 查找(返回一个对象)

  207. * @param collection
  208. * @param q
  209. *            查询条件
  210. */
  211. public DBObject findOne(String collection, DBObject q) {
  212. return findOne(collection, q, null);
  213. }
  214. /**
  215. * 查找(返回一个对象)

  216. * @param collection
  217. * @param q
  218. *            查询条件
  219. * @param fileds
  220. *            返回字段
  221. */
  222. public DBObject findOne(String collection, DBObject q, DBObject fields) {
  223. if (q.containsField(DB_ID)) {// 如果根据id来查询,先从缓存取数据
  224. DBObject tmp = MC.<DBObject> get(DBObject.class,
  225. (Long) q.get(DB_ID));
  226. if (tmp != null) {// 缓存没有数据,从数据库取
  227. if (fields != null) {// 留下需要返回的字段
  228. for (String key : tmp.keySet()) {
  229. if (!fields.containsField(key)) {
  230. tmp.removeField(key);
  231. }
  232. }
  233. }
  234. return tmp;
  235. }
  236. }
  237. return fields == null ? getCollection(collection).findOne(q)
  238. : getCollection(collection).findOne(q, fields);
  239. }
  240. /**
  241. * 查找返回特定字段(返回一个List<DBObject>)

  242. * @param collection
  243. * @param q
  244. *            查询条件
  245. * @param fileds
  246. *            返回字段
  247. */
  248. public List<DBObject> findLess(String collection, DBObject q,
  249. DBObject fileds) {
  250. DBCursor c = getCollection(collection).find(q, fileds);
  251. if (c != null)
  252. return c.toArray();
  253. else
  254. return null;
  255. }
  256. /**
  257. * 查找返回特定字段(返回一个List<DBObject>)

  258. * @param collection
  259. * @param q
  260. *            查询条件
  261. * @param fileds
  262. *            返回字段
  263. * @param orderBy
  264. *            排序
  265. */
  266. public List<DBObject> findLess(String collection, DBObject q,
  267. DBObject fileds, DBObject orderBy) {
  268. DBCursor c = getCollection(collection).find(q, fileds).sort(orderBy);
  269. if (c != null)
  270. return c.toArray();
  271. else
  272. return null;
  273. }
  274. /**
  275. * 分页查找集合对象,返回特定字段

  276. * @param collection
  277. * @param q
  278. *            查询条件
  279. * @param fileds
  280. *            返回字段
  281. * @pageNo 第n页
  282. * @perPageCount 每页记录数
  283. */
  284. public List<DBObject> findLess(String collection, DBObject q,
  285. DBObject fileds, int pageNo, int perPageCount) {
  286. return getCollection(collection).find(q, fileds)
  287. .skip((pageNo - 1) * perPageCount).limit(perPageCount)
  288. .toArray();
  289. }
  290. /**
  291. * 按顺序分页查找集合对象,返回特定字段

  292. * @param collection
  293. *            集合
  294. * @param q
  295. *            查询条件
  296. * @param fileds
  297. *            返回字段
  298. * @param orderBy
  299. *            排序
  300. * @param pageNo
  301. *            第n页
  302. * @param perPageCount
  303. *            每页记录数
  304. */
  305. public List<DBObject> findLess(String collection, DBObject q,
  306. DBObject fileds, DBObject orderBy, int pageNo, int perPageCount) {
  307. return getCollection(collection).find(q, fileds).sort(orderBy)
  308. .skip((pageNo - 1) * perPageCount).limit(perPageCount)
  309. .toArray();
  310. }
  311. /**
  312. * 查找(返回一个List<DBObject>)

  313. * @param collection
  314. * @param q
  315. *            查询条件
  316. */
  317. public List<DBObject> find(String collection, DBObject q) {
  318. DBCursor c = getCollection(collection).find(q);
  319. if (c != null)
  320. return c.toArray();
  321. else
  322. return null;
  323. }
  324. /**
  325. * 按顺序查找(返回一个List<DBObject>)

  326. * @param collection
  327. * @param q
  328. *            查询条件
  329. * @param orderBy
  330. *            排序
  331. */
  332. public List<DBObject> find(String collection, DBObject q, DBObject orderBy) {
  333. DBCursor c = getCollection(collection).find(q).sort(orderBy);
  334. if (c != null)
  335. return c.toArray();
  336. else
  337. return null;
  338. }
  339. /**
  340. * 分页查找集合对象

  341. * @param collection
  342. * @param q
  343. *            查询条件
  344. * @pageNo 第n页
  345. * @perPageCount 每页记录数
  346. */
  347. public List<DBObject> find(String collection, DBObject q, int pageNo,
  348. int perPageCount) {
  349. return getCollection(collection).find(q)
  350. .skip((pageNo - 1) * perPageCount).limit(perPageCount)
  351. .toArray();
  352. }
  353. /**
  354. * 按顺序分页查找集合对象

  355. * @param collection
  356. *            集合
  357. * @param q
  358. *            查询条件
  359. * @param orderBy
  360. *            排序
  361. * @param pageNo
  362. *            第n页
  363. * @param perPageCount
  364. *            每页记录数
  365. */
  366. public List<DBObject> find(String collection, DBObject q, DBObject orderBy,
  367. int pageNo, int perPageCount) {
  368. return getCollection(collection).find(q).sort(orderBy)
  369. .skip((pageNo - 1) * perPageCount).limit(perPageCount)
  370. .toArray();
  371. }
  372. /**
  373. * distinct操作

  374. * @param collection
  375. *            集合
  376. * @param field
  377. *            distinct字段名称
  378. */
  379. public Object[] distinct(String collection, String field) {
  380. return getCollection(collection).distinct(field).toArray();
  381. }
  382. /**
  383. * distinct操作

  384. * @param collection
  385. *            集合
  386. * @param field
  387. *            distinct字段名称
  388. * @param q
  389. *            查询条件
  390. */
  391. public Object[] distinct(String collection, String field, DBObject q) {
  392. return getCollection(collection).distinct(field, q).toArray();
  393. }
  394. /**
  395. * group分组查询操作,返回结果少于10,000keys时可以使用

  396. * @param collection
  397. *            集合
  398. * @param key
  399. *            分组查询字段
  400. * @param q
  401. *            查询条件
  402. * @param reduce
  403. *            reduce Javascript函数,如:function(obj,
  404. *            out){out.count++;out.csum=obj.c;}
  405. * @param finalize
  406. *            reduce
  407. *            function返回结果处理Javascript函数,如:function(out){out.avg=out.csum
  408. *            /out.count;}
  409. */
  410. public BasicDBList group(String collection, DBObject key, DBObject q,
  411. DBObject initial, String reduce, String finalize) {
  412. return ((BasicDBList) getCollection(collection).group(key, q, initial,
  413. reduce, finalize));
  414. }
  415. /**
  416. * group分组查询操作,返回结果大于10,000keys时可以使用

  417. * @param collection
  418. *            集合
  419. * @param map
  420. *            映射javascript函数字符串,如:function(){ for(var key in this) {
  421. *            emit(key,{count:1}) } }
  422. * @param reduce
  423. *            reduce Javascript函数字符串,如:function(key,emits){ total=0; for(var
  424. *            i in emits){ total+=emits[i].count; } return {count:total}; }
  425. * @param q
  426. *            分组查询条件
  427. * @param orderBy
  428. *            分组查询排序
  429. */
  430. public Iterable<DBObject> mapReduce(String collection, String map,
  431. String reduce, DBObject q, DBObject orderBy) {
  432. // DBCollection coll = db.getCollection(collection);
  433. // MapReduceCommand cmd = new MapReduceCommand(coll, map, reduce, null,
  434. // MapReduceCommand.OutputType.INLINE, q);
  435. // return coll.mapReduce(cmd).results();
  436. MapReduceOutput out = getCollection(collection).mapReduce(map, reduce,
  437. null, q);
  438. return out.getOutputCollection().find().sort(orderBy).toArray();
  439. }
  440. /**
  441. * group分组分页查询操作,返回结果大于10,000keys时可以使用

  442. * @param collection
  443. *            集合
  444. * @param map
  445. *            映射javascript函数字符串,如:function(){ for(var key in this) {
  446. *            emit(key,{count:1}) } }
  447. * @param reduce
  448. *            reduce Javascript函数字符串,如:function(key,emits){ total=0; for(var
  449. *            i in emits){ total+=emits[i].count; } return {count:total}; }
  450. * @param q
  451. *            分组查询条件
  452. * @param orderBy
  453. *            分组查询排序
  454. * @param pageNo
  455. *            第n页
  456. * @param perPageCount
  457. *            每页记录数
  458. */
  459. public List<DBObject> mapReduce(String collection, String map,
  460. String reduce, DBObject q, DBObject orderBy, int pageNo,
  461. int perPageCount) {
  462. MapReduceOutput out = getCollection(collection).mapReduce(map, reduce,
  463. null, q);
  464. return out.getOutputCollection().find().sort(orderBy)
  465. .skip((pageNo - 1) * perPageCount).limit(perPageCount)
  466. .toArray();
  467. }
  468. /**
  469. * group分组查询操作,返回结果大于10,000keys时可以使用

  470. * @param collection
  471. *            集合
  472. * @param map
  473. *            映射javascript函数字符串,如:function(){ for(var key in this) {
  474. *            emit(key,{count:1}) } }
  475. * @param reduce
  476. *            reduce Javascript函数字符串,如:function(key,emits){ total=0; for(var
  477. *            i in emits){ total+=emits[i].count; } return {count:total}; }
  478. * @param outputCollectionName
  479. *            输出结果表名称
  480. * @param q
  481. *            分组查询条件
  482. * @param orderBy
  483. *            分组查询排序
  484. */
  485. public List<DBObject> mapReduce(String collection, String map,
  486. String reduce, String outputCollectionName, DBObject q,
  487. DBObject orderBy) {
  488. if (!db.collectionExists(outputCollectionName)) {
  489. getCollection(collection).mapReduce(map, reduce,
  490. outputCollectionName, q);
  491. }
  492. return getCollection(outputCollectionName)
  493. .find(null, new BasicDBObject("_id", false)).sort(orderBy)
  494. .toArray();
  495. }
  496. /**
  497. * group分组分页查询操作,返回结果大于10,000keys时可以使用

  498. * @param collection
  499. *            集合
  500. * @param map
  501. *            映射javascript函数字符串,如:function(){ for(var key in this) {
  502. *            emit(key,{count:1}) } }
  503. * @param reduce
  504. *            reduce Javascript函数字符串,如:function(key,emits){ total=0; for(var
  505. *            i in emits){ total+=emits[i].count; } return {count:total}; }
  506. * @param outputCollectionName
  507. *            输出结果表名称
  508. * @param q
  509. *            分组查询条件
  510. * @param orderBy
  511. *            分组查询排序
  512. * @param pageNo
  513. *            第n页
  514. * @param perPageCount
  515. *            每页记录数
  516. */
  517. public List<DBObject> mapReduce(String collection, String map,
  518. String reduce, String outputCollectionName, DBObject q,
  519. DBObject orderBy, int pageNo, int perPageCount) {
  520. if (!db.collectionExists(outputCollectionName)) {
  521. getCollection(collection).mapReduce(map, reduce,
  522. outputCollectionName, q);
  523. }
  524. return getCollection(outputCollectionName)
  525. .find(null, new BasicDBObject("_id", false)).sort(orderBy)
  526. .skip((pageNo - 1) * perPageCount).limit(perPageCount)
  527. .toArray();
  528. }
  529. /**
  530. * @Title: getServerAddress
  531. * @Description: 获取数据库服务器列表
  532. * @param dbName
  533. * @return
  534. * @throws UnknownHostException
  535. * @return List<ServerAddress>
  536. * @throws
  537. */
  538. private static List<ServerAddress> getServerAddress(String dbName)
  539. throws UnknownHostException {
  540. List<ServerAddress> list = new ArrayList<ServerAddress>();
  541. String hosts = getProperty(CONF_PATH, dbName + ".host");
  542. for (String host : hosts.split("&")) {
  543. String ip = host.split(":")[0];
  544. String port = host.split(":")[1];
  545. list.add(new ServerAddress(ip, Integer.parseInt(port)));
  546. }
  547. return list;
  548. }
  549. /**
  550. * @Title: getMongoCredential
  551. * @Description: 获取数据库安全验证信息
  552. * @param dbName
  553. * @return
  554. * @return List<MongoCredential>
  555. * @throws
  556. */
  557. private static List<MongoCredential> getMongoCredential(String dbName) {
  558. String username = getProperty(CONF_PATH, dbName + ".username");
  559. String password = getProperty(CONF_PATH, dbName + ".password");
  560. String database = getProperty(CONF_PATH, dbName + ".database");
  561. MongoCredential credentials = MongoCredential.createMongoCRCredential(
  562. username, database, password.toCharArray());
  563. List<MongoCredential> credentialsList = new ArrayList<MongoCredential>();
  564. credentialsList.add(credentials);
  565. return credentialsList;
  566. }
  567. /**
  568. * @Title: getDBOptions
  569. * @Description: 获取数据参数设置
  570. * @return
  571. * @return MongoClientOptions
  572. * @throws
  573. */
  574. private static MongoClientOptions getDBOptions(String dbName) {
  575. MongoClientOptions.Builder build = new MongoClientOptions.Builder();
  576. build.connectionsPerHost(Integer.parseInt(getProperty(CONF_PATH, dbName
  577. + ".connectionsPerHost"))); // 与目标数据库能够建立的最大connection数量为50
  578. build.threadsAllowedToBlockForConnectionMultiplier(Integer
  579. .parseInt(getProperty(CONF_PATH, dbName
  580. + ".threadsAllowedToBlockForConnectionMultiplier"))); // 如果当前所有的connection都在使用中,则每个connection上可以有50个线程排队等待
  581. build.maxWaitTime(Integer.parseInt(getProperty(CONF_PATH, dbName
  582. + ".maxWaitTime")));
  583. build.connectTimeout(Integer.parseInt(getProperty(CONF_PATH, dbName
  584. + ".connectTimeout")));
  585. MongoClientOptions myOptions = build.build();
  586. return myOptions;
  587. }
  588. public static void main(String[] args) {
  589. try {
  590. // getInstance().insert(
  591. // "user",
  592. // new BasicDBObject().append("name", "admin3")
  593. // .append("type", "2").append("score", 70)
  594. // .append("level", 2)
  595. // .append("inputTime", new Date().getTime()));
  596. // getInstance().update("user",
  597. // new BasicDBObject().append("status", 1),
  598. // new BasicDBObject().append("status", 2));
  599. // === group start =============
  600. // StringBuilder sb = new StringBuilder(100);
  601. // sb.append("function(obj, out){out.count++;out.").append("scoreSum")
  602. // .append("+=obj.").append("score").append(";out.")
  603. // .append("levelSum").append("+=obj.").append("level")
  604. // .append('}');
  605. // String reduce = sb.toString();
  606. // BasicDBList list = getInstance().group(
  607. // "user",
  608. // new BasicDBObject("type", true),
  609. // new BasicDBObject(),
  610. // new BasicDBObject().append("count", 0)
  611. // .append("scoreSum", 0).append("levelSum", 0)
  612. // .append("levelAvg", (Double) 0.0), reduce,
  613. // "function(out){ out.levelAvg = out.levelSum / out.count }");
  614. // for (Object o : list) {
  615. // DBObject obj = (DBObject) o;
  616. // System.out.println(obj);
  617. // }
  618. // ======= group end=========
  619. // === mapreduce start =============
  620. // Iterable<DBObject> list2 = getInstance()
  621. // .mapReduce(
  622. // "user",
  623. // "function(){emit( {type:this.type}, {score:this.score, level:this.level} );}",
  624. // "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;}",
  625. // new BasicDBObject(), new BasicDBObject("score", 1));
  626. // for (DBObject o : list2) {
  627. // System.out.println(o);
  628. // }
  629. // List<DBObject> list3 = getInstance().mapReduce("user",
  630. // "function(){emit({type:this.type},{type:this.type,score:this.score,level:this.level});}",
  631. // "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;}",
  632. // "group_temp_user",
  633. // new BasicDBObject(),
  634. // new BasicDBObject("score",1));
  635. // for (DBObject o : list3) {
  636. // System.out.println(o);
  637. // }
  638. // ======= mapreduce end=========
  639. // System.out.print(getInstance().findAll("user"));
  640. // System.out.print(getInstance().find(
  641. // "user",
  642. // new BasicDBObject("inputTime", new BasicDBObject("$gt",
  643. // 1348020002890L)),
  644. // new BasicDBObject().append("_id", "-1"), 1, 2));
  645. // getInstance().delete("user", new BasicDBObject());
  646. } catch (Exception e) {
  647. System.out.println(e.getMessage());
  648. }
  649. }
  650. }

以下是mongo的连接配置properties文件

  1. #ip和端口,多个主机用&相连
  2. db.host=127.0.0.1:27017
  3. #数据库名字
  4. db.database=war
  5. #用户名
  6. db.username=root
  7. #密码
  8. db.password=123456
  9. #每个主机的最大连接数
  10. db.connectionsPerHost=50
  11. #线程允许最大等待连接数
  12. db.threadsAllowedToBlockForConnectionMultiplier=50
  13. #连接超时时间1分钟
  14. db.connectTimeout=60000
  15. #一个线程访问数据库的时候,在成功获取到一个可用数据库连接之前的最长等待时间为2分钟
  16. #这里比较危险,如果超过maxWaitTime都没有获取到这个连接的话,该线程就会抛出Exception
  17. #故这里设置的maxWaitTime应该足够大,以免由于排队线程过多造成的数据库访问失败
  18. db.maxWaitTime=120000

DBObject和Javabean之间的转换就容易多了,可以通过json为中介来转换。

  1. public class DBObjectUtil {
  2. /**
  3. * 把实体bean对象转换成DBObject

  4. * @param bean
  5. * @return
  6. * @throws IllegalArgumentException
  7. * @throws IllegalAccessException
  8. */
  9. public static <T> DBObject bean2DBObject(T bean) {
  10. if (bean == null) {
  11. return null;
  12. }
  13. DBObject dbObject = new BasicDBObject();
  14. String json = JsonUtils.objectToJson(bean);
  15. dbObject = (DBObject) JSON.parse(json);
  16. return dbObject;
  17. }
  18. /**
  19. * 把DBObject转换成bean对象

  20. * @param dbObject
  21. * @param bean
  22. * @return
  23. * @throws IllegalAccessException
  24. * @throws InvocationTargetException
  25. * @throws NoSuchMethodException
  26. */
  27. @SuppressWarnings("unchecked")
  28. public static <T> T dbObject2Bean(DBObject dbObject, T bean) {
  29. if (bean == null) {
  30. return null;
  31. }
  32. String json = JSON.serialize(dbObject);
  33. bean = (T) JsonUtils.jsonToBean(json, bean.getClass());
  34. return bean;
  35. }
  36. }

至此,mongo搭建基本完成,更多关于mongo的探索,还是要在实践中完成,实践是检验真理的唯一标准,nosql如今炙手可热,但我们也要保持理性的态度看待问题,传统数据库和nosql究竟谁更胜一筹,不妨我们都动手试一试,是骡子是马,都拉出来溜溜!以上代码可直接用过工具类,欢迎交流探讨!

Java游戏服务器成长之路——你好,Mongo的更多相关文章

  1. Java游戏服务器成长之路——感悟篇

    又是一个美好的周末啊,现在一到周末,早上就起得晚,下午困了又会睡一两个小时,上班的时候,早上起来喝一杯咖啡,然后就能高效的工作一整天,然而到了周末人就懒散了,哈哈. 最近刚跳槽,到新公司已经干了有两周 ...

  2. Java游戏服务器成长之路——弱联网游戏篇(源码分析)

    前言 前段时间由于公司的一款弱联网游戏急着上线,没能及时分享,现在基本做的差不多,剩下的就是测试阶段了(本来说元旦来分享一下服务器技术的).公司的这款游戏已经上线一年多了,在我来之前一直都是单机版本, ...

  3. Java游戏服务器搭建

    一.前言 此游戏服务器架构是一个单服的形式,也就是说所有游戏逻辑在一个工程里,没有区分登陆服务器.战斗服务器.世界服务器等.此架构已成功应用在了多款页游服务器 .在此框架中没有实现相关业务逻辑,只有简 ...

  4. 分享下对JAVA程序员成长之路的总结<转>

    我也搞了几年JAVA了,由于一向懒惰,没有成为大牛,只是一普通程序猿,手痒来给新人分享下从新手成长为老鸟的已见.   首先初识语法的阶段,必须要学会怎么操作对象,操作if和for,操作list set ...

  5. 【转载】分享下多年积累的对JAVA程序员成长之路的总结

    注:该文是从百度贴吧转载过来,之前看到觉得写得还不错,对Java开发学习者来说很有意义的,可以看看. 我也搞了几年JAVA了,由于一向懒惰,没有成为大牛,只是一普通程序猿,不爱玩社交网站,不爱玩微博, ...

  6. 一个JAVA程序员成长之路分享

    我搞JAVA也有些日子了, 因为我比较贪玩,上进心不那么强, 总是逼不得已为了高薪跳槽才去学习, 所以也没混成什么大牛, 但好在现在也已经成家立业, 小日子过的还算滋润, 起码顶得住一月近万元的吃喝拉 ...

  7. 分享下多年积累的对JAVA程序员成长之路的总结

    http://blog.csdn.net/zhongzelin/article/details/8643269我也搞了几年JAVA了,由于一向懒惰,没有成为大牛,只是一普通程序猿,不爱玩社交网站,不爱 ...

  8. java实习生的成长之路<转>

    首先初识语法的阶段,必须要学会怎么操作对象,操作if和for,操作list set map,然后是线程.IO和jdbc什么的,其余的,若是一时不理解,可以后边需要时再学. 这阶段完了,你可以写些能在控 ...

  9. Java程序的成长之路

    转载链接:http://www.admin10000.com/document/2901.html 互联网发展日新月异,社会科技每天都在发生着翻天覆地的变化,而程序员已经成了这个时代的庞大群体,各种各 ...

随机推荐

  1. SQLServer------Sql Server性能优化辅助指标SET STATISTICS TIME ON和SET STATISTICS IO ON

    转载: http://www.cnblogs.com/xqhppt/p/4041799.html

  2. 工作流JBPM_day02:1-回顾_2-设计流程Transition

    工作流JBPM_day02:1-回顾 1,工作流框架 处理流程的 流程多,有变化 2,准备环境 + HelloWorld 一.概念 Deployment部署对象 ProcessDefinition 流 ...

  3. MySQL<多表操作>

    多表操作 外键 什么是外键 外键是指引用另一个表中的一列或多列,被引用的列应该具有主键约束或唯一性约束. 外键用于建立和加强两个表数据之间的链接. 为表添加外键约束 想要真正连接两个表的数据,就需要为 ...

  4. try catch finally的执行顺序

    1.将预见可能引发异常的代码包含在try语句块中. 2.如果发生了异常,则转入catch的执行.catch有几种写法: catch 这将捕获任何发生的异常. catch(Exception e) 这将 ...

  5. 服务端用例设计的思(tao)路!

    服务端的测试简单来说就是除了前端以外的的测试. 总的来说可以分为以下两类: 1.     WEB或者APP的提供业务逻辑的服务端接口测试 2.     数据库.缓存系统.中间件..jar包依赖.输入输 ...

  6. python2.0_day18_Django自带的用户认证模块的使用

    用户验证我们基于一个项目来学习利用Django框架中的user表实现用户认证Django练习小项目:学员管理系统设计开发 项目需求: 1.分讲师\学员\课程顾问角色, 2.学员可以属于多个班级,学员成 ...

  7. UE4修改自Rama的UDP通信蓝图插件

    UE4.15没有提供蓝图UDP的组件,可以在网上找到一个ID叫Rama写的源代码,我把它封装成插件了(MyUdpPlugin),方便在各个UE4版本工程中使用UDP通信. 使用方式: 1.在自己的工程 ...

  8. C# EMS Client

    从 C# 客户端连接 Tibco EMS 下面例子简要介绍 C# 客户端怎样使用 TIBCO.EMS.dll 来连接 EMS 服务器. using System; using System.Diagn ...

  9. 问答项目---登陆也要做验证!(JS和PHP验证)

    简单JS示例: var login = $( 'form[name=login]' ); login.submit( function () { if (validate.loginAccount & ...

  10. Linux(Centos)下搭建SVN服务器

    鉴于在搭建时,参考网上很多资料,网上资料在有用的同时,也坑了很多人,本文的目的,也就是想让后继之人在搭建svn服务器时不再犯错,不再被网上漫天的坑爹作品所坑害,故此总结! /******开始***** ...