MongoDB初始化
首先在SimpleServer解决方案里添加新的类库,命名为MongoDB。
打开Nuget包管理器,搜索“MongoDB”,给MongoDB项目添加“MongoDB.Bson”、“MongoDB.Driver.Core”和“MongoDB.Driver”,然后再引用ServerBase项目。
给SimpleServer项目添加MongoDB项目的引用。
在MongoDB项目添加MongoDBMgr
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| using MongoDB.Driver;
namespace MongoDB { public class MongoDBMgr : SingletonPattern<MongoDBMgr> { private const string m_DBConnect = "mongodb://127.0.0.1:27017"; private const string m_DBName = "MongoDBLearn";
protected static IMongoClient? m_Client; protected static IMongoDatabase? m_Database; public void Init() { var mongoUrl = new MongoUrlBuilder(m_DBConnect); m_Client = new MongoClient(mongoUrl.ToMongoUrl()); m_Database = m_Client.GetDatabase(m_DBName); } } }
|
初始化分三步:创建数据库链接,从链接创建客户端,从客户端获取数据库。
在SimpleServer项目的Program.cs里面初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| using SimpleServer.Net; using MongoDB; using MySql;
namespace SimpleServer { internal class Program { static void Main(string[] args) { MySqlMgr.Instance.Init(); MongoDBMgr.Instance.Init(); ServerSocket.Instance.Init(); Console.ReadLine(); } } }
|
实体类
和使用SqlSugar一样,要记录进数据库就需要对应的实体类。
在MongoDB项目内新建MongoDBData文件夹。在其中新建PlayerAction.cs文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes;
namespace MongoDB.MongoDBData { public class PlayerAction { public ObjectId _id { get; set; } public string? Key { get;set; } public string? Data { get;set; } [BsonDateTimeOptions(Kind = DateTimeKind.Local)] public DateTime? Time { get; set; } } }
|
ObjectId的构成:
之前我们使用MySQL等关系型数据库时,主键都是设置成自增的。但在MongoDB这种分布式数据库环境下,自增主键就不可行了,会产生冲突。为此,MongoDB采用了一个称之为ObjectId的类型来做主键。ObjectId是一个12字节的 BSON 类型字符串。按照字节顺序,一次代表:
4字节:UNIX时间戳
3字节:表示运行MongoDB的机器
2字节:表示生成此_id的进程
3字节:由一个随机数开始的计数器生成的值
从ObjectId的构造上来看,内部就嵌入了时间类型。我们肯定可以从中获取时间信息:即插入此文档时的时间。MongoDB对ObjectId对象提供了getTimestamp()方法来获取ObjectId的时间。
增加玩家行为记录(使用BsonDoc)
在MongoDBMgr
中添加AddAction
添加玩家行为的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
public bool AddAction(int userId,string name,string key,string data) { try { string collectionName = "UserAction_" + userId + "_" + name; var collection = m_Database?.GetCollection<BsonDocument>(collectionName); var document = new BsonDocument { { "Key", key } , { "Data", data }, { "Time", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ffff") } }; collection?.InsertOne(document); return true; } catch (Exception ex) { Debug.LogError("玩家行为写入错误:" + ex.ToString()); return false; } }
|
注意:
添加玩家行为是不断递增的表,在插入时不需要判断有没有记录。
玩家的记录有限,到达一定数据量(10000条)时会删除旧的。
这里我们使用BsonDocument
来添加记录,BsonDocument
可以直接添加记录,不需要实体类。
查找玩家行为记录
MongoDB提供了流式(fluent)查找的API。IMongoCollection<T>.Find<T>
在MongoDBMgr
中添加FindAction
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
public void FindAction(int userId, string name) { try { string collectionName = "UserAction_" + userId + "_" + name; var collection = m_Database?.GetCollection<BsonDocument>(collectionName); var dataList = collection.Find(new BsonDocument()).ToList(); foreach (var data in dataList) { Debug.Log(data.ToString()); } } catch (Exception ex) { Debug.LogError("玩家行为查询错误:" + ex); } }
|
增加玩家行为记录(使用泛型)
在MongoDBMgr
中添加Add
泛型方法,主要使用InsertOne
,然后再在AddAction
调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| public bool AddAction(int userId,string name,string key,string data) { try { string collectionName = "UserAction_" + userId + "_" + name; PlayerAction playerAction = new PlayerAction(); playerAction.Key = key; playerAction.Data = data; playerAction.Time = DateTime.Now; return Add(playerAction, collectionName); } catch (Exception ex) { Debug.LogError("玩家行为写入错误:" + ex.ToString()); return false; } }
public bool Add<T>(T entity,string collName) where T : class,new() { try { var collection = m_Database?.GetCollection<T>(collName); if (collection != null) { collection.InsertOne(entity); return true; } return false; } catch (Exception ex) { Debug.LogError("MongoDB添加数据错误:" + ex ); return false; } }
|
当然,不使用包装好的泛型方法也可以
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
public bool AddAction(int userId,string name,string key,string data) { try { string collectionName = "UserAction_" + userId + "_" + name; var collection = m_Database?.GetCollection<PlayerAction>(collectionName); PlayerAction playerAction = new PlayerAction(); playerAction.Key = key; playerAction.Data = data; playerAction.Time = DateTime.Now; collection?.InsertOne(playerAction); return true; } catch (Exception ex) { Debug.LogError("玩家行为写入错误:" + ex.ToString()); return false; } }
|
增加玩家行为记录(异步方法)
MongoDB也提供了异步增加数据的APIInsertOneAsync
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
public async Task<bool> AddAsync<T>(T entity, string collName) where T : class, new() { try { var collection = m_Database?.GetCollection<T>(collName); if (collection != null) { await collection.InsertOneAsync(entity); return true; } else { return false; } } catch (Exception ex) { Debug.LogError("MongoDB异步添加数据错误:" + ex); return false; } }
|
增加多条记录(使用泛型)
MongoDB提供了批量增加数据的APIInsertMany
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
public bool InsertMany<T>(List<T> entities, string collName) where T : class, new() { try { var collection = m_Database?.GetCollection<T>(collName); if (collection != null) { collection.InsertMany(entities); return true; } return false; } catch (Exception ex) { Debug.LogError("MongoDB批量添加数据错误:" + ex); return false; } }
|
增加多条记录(异步方法)
MongoDB提供了异步批量增加数据的APIInsertManyAsync
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
public async Task<bool> InsertManyAsync<T>(List<T> entities, string collName) where T : class, new() { try { var collection = m_Database?.GetCollection<T>(collName); if (collection != null) { await collection.InsertManyAsync(entities); return true; } else { return false; } } catch (Exception ex) { Debug.LogError("MongoDB异步批量添加数据错误:" + ex); return false; } }
|
注意,所有添加记录操作能成功的前提是MongoDB中有这个玩家的表。而MongoDB可以隐式增加表,也就是说如果没有这个表会按照表名自动创建。