最近项目要求做一个主要业务的操作日志,保存后供追溯查询。由于需要较高的写入性能,且不用繁琐的关系存储,思来想去nosql适合。
在比较redis和mongodb后决定采用后者,原因只有一个,后者支持方便的条件查询……
1、先说环境搭建(Windows 10),先进入官网https://www.mongodb.com/download-center?jmp=nav#community下载最新的3.2版本,是否需要with SSL看项目需求。
2、下载完成直接点击安装,安装完成后:
1):手动创建dbpath路径
2):将mongodb安装为service,以admin权限启动cmd输入命令:
mongod.exe --bind_ip 127.0.0.1 --logpath "D:\MongoDB\dbConf\mongodb.log" --logappend --dbpath "D:\MongoDB\db" --serviceName "MongoDB" --serviceDisplayName "MongoDB" --install
其中, bind_ip:指定访问数据的主机ip,这里仅限本地;
logpath:log文件路径,自主指定;
logappend:追加形式写log;
dbpath:即上面创建好的dbpath;
serviceName:服务名称;
serviceDisplayName;显示的服务名称;
3)、启动服务:net start MongoDB
3、进入安装目录运行mongo即可打开console,常用命令:
Show dbs-------所有数据库
Use [dbname] -------进入指定数据库
Show collections-------显示所有集合(相当于tsql的table)
Db.[collectionname].find()-------查询集合所有数据
Db.[collectionname].drop()-------删除集合,如果当前只有一个集合,那么将删除db
其他命令可分别使用db.help()和db.[collectionname].help()查询
4、环境配置完毕,添加驱动,这里使用的是官方最新1.11版,可以在VisualStudio中使用NuGet工具直接添加:
1)在NuGet中搜索mongodb,请选择第二个mongocsharpdriver;
2)添加完毕后会多出两个dll:MongoDB.Driver.dll和MongoDB.Bson.XML;
3)官方1.x和2.x驱动的api是不同的,要注意。
5、驱动使用方法见如下provider,由于业务层使用了泛型,这里用了比较多的判断:
using _5yue.Common; using _5yue.Models; using MongoDB.Bson; using MongoDB.Driver; using MongoDB.Driver.Builders; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _5yue.Data.MongoDB { public class MongoDBProvider { private static string serverAddress = "mongodb://localhost:27017"; private static string mongoDbName = "db_name"; //private MongoServer server; private MongoClient client = null; private MongoDatabase database = null; private MongoCollection collection = null; public MongoDBProvider(string collectionName) { if (collection == null) { client = new MongoClient(serverAddress);// 打开连接 database = client.GetServer().GetDatabase(mongoDbName);// 打开数据库 collection = database.GetCollection(collectionName);// 打开集合(相当于表) } else if (!collection.Name.Equals(collectionName)) { collection = database.GetCollection(collectionName);// 更换集合 } } #region 插入 public void InsertObj<T>(T document)// 单条 { collection.Insert<T>(document); } public void InsertBson(BsonDocument bDoc)// 插入单条bson { collection.Insert(bDoc); } public void InsertObjList<T>(IList<T> objs)// 多条 { collection.InsertBatch<T>(objs); } #endregion #region 查询 public MongoCursor<T> GetAll<T>() { return collection.FindAllAs<T>(); } /// <summary> /// 通过条件获取结果 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="user"></param> /// <param name="entityId"></param> /// <param name="minTime"></param> /// <param name="maxTime"></param> /// <returns></returns> public MongoCursor<T> GetByCondition<T>(OperateLogModel olModel) { if (olModel != null && parameterNameList != null && parameterNameList.Count > 0) { List<IMongoQuery> list = new List<IMongoQuery>(); list.Add(Query.EQ("paras", olModel.operatorId));// paras:db中存放的字段,olModel.operatorId: 传过来的查询条件 if (list.Count > 0) { var query = Query.And(list);// 条件连接 //return collection.FindAs<T>(Query.EQ("CreaterId", 2)); return collection.FindAs<T>(query); } else { return collection.FindAllAs<T>(); } } else return null; } #endregion #region 工具 public void ChangeCollection(string collectionName) { collection = database.GetCollection(collectionName); } public MongoDatabase GetDB() { return database == null ? database : null; } public MongoCollection GetCollection() { return collection == null ? collection : null; } /// <summary> /// 把MongoCursor转换成List类型 /// </summary> /// <param name="cursor">文档游标</param> /// <returns></returns> public List<T> CursorToList<T>(MongoCursor<T> cursor) { List<T> resultList = new List<T>(); cursor.GetEnumerator().MoveNext();// 设置游标 if(cursor.Count() > 0) { foreach (var obj in cursor)// 遍历 { resultList.Add(obj); } } return resultList; } #endregion } }
点击显示
6、业务类:
using _lbh.Models; using _lbh.Data.MongoDB; using MongoDB.Bson; using MongoDB.Driver; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using _lbh.Common; namespace _lbh.DataProvider { /// <summary> /// 操作日志 /// </summary> public class OperateLog : BaseProvider { public static MongoDBProvider mDBProvider = null; /// <summary> /// 初始化mongoDB /// </summary> /// <param name="collectionName">集合名称</param> public static void InitMongoDB(string collectionName) { if (mDBProvider == null)// 为空就初始化 { mDBProvider = new MongoDBProvider(collectionName); } else if (!collectionName.Equals(mDBProvider.GetCollection()))// 如不是当前集合 { mDBProvider.ChangeCollection(collectionName);// 修改为当前集合 } } #region 插入 /// <summary> /// 直接插入实体对象 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="obj"></param> /// <param name="collectionName"></param> public static void Insert<T>(T obj, string collectionName) { InitMongoDB(collectionName); mDBProvider.InsertObj<T>(obj); } /// <summary> /// 直接插入对象列表 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="objList"></param> /// <param name="collectionName"></param> public static void InsertList<T>(List<T> objList, string collectionName) { InitMongoDB(collectionName); mDBProvider.InsertObjList<T>(objList); } #endregion #region 查询 /// <summary> /// 获取指定集合的所有数据,无论是否Bson形式 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="model"></param> /// <returns></returns> public static List<T> GetAll<T>(OperateLogModel model) { if (model == null || Utils.StrIsNullOrEmpty(model.collectionName)) { return null; } InitMongoDB(model.collectionName); MongoCursor<T> result = mDBProvider.GetAll<T>(); List<T> resultList = mDBProvider.CursorToList<T>(result); return resultList; } /// <summary> /// 指定条件查询 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="model"></param> /// <returns></returns> public static List<T> GetLByCondition<T>(OperateLogModel model) { if (model == null || Utils.StrIsNullOrEmpty(model.collectionName)) { return null; } InitMongoDB(model.collectionName); MongoCursor<T> result = mDBProvider.GetByCondition<T>(model);// 获取查询结果 List<T> resultList = mDBProvider.CursorToList<T>(result);// 数据结构转换 return resultList; } #endregion } }
点击显示
7、条件Model定义:
// 这是查询用的条件model public class OperateLogModel { /// <summary> /// 集合名称_集合为nosql存放数据的单位,相当于rdb的表 /// </summary> public string collectionName { get; set; } /// <summary> /// 操作员id /// </summary> public int operatorId { get; set; } /// <summary> /// 操作员名称 /// </summary> public string operatorName { get; set; } /// <summary> /// 实体对象id /// </summary> public string entityId { get; set; } /// <summary> /// 查询时间下限 /// </summary> [BsonDateTimeOptions(Kind = DateTimeKind.Local)] public DateTime minTime { get; set; } /// <summary> /// 查询时间上限 /// </summary> [BsonDateTimeOptions(Kind = DateTimeKind.Local)] public DateTime maxTime { get; set; } }
点击打开
8、数据实体Model定义: 略
9、业务入口调用:
插入:OperateLog.InsertList<OrderModel>(pList, "OrderModel");
查询:List<OrderModel> sa = OperateLog.GetLByCondition<OrderModel>(new OperateLogModel(););
10、补充:
1)、MongoDB内部已实现了较完善的线程池,所以多数情境下不用考虑。
2)、MongoDB存储时将日期字段转为UTC标准(即比北京时间晚8小时),需要在相关Model的时间字段添加[BsonDateTimeOptions(Kind = DateTimeKind.Local)]修饰。
3)、使用官方驱动的弊端之一,实体Model中必须包含ObjectId _id字段,此字段将作为默认主键保存在库中。处理手段之一是使用collection.Insert(Bson bson)插入数据,Bson结果类似Json,db内部也是以此存取数据。
4)、想到再说……
总结,本项目中只算非常入门的使用MongoDB,至于分布式存储、同步等特性还有待挖掘,本人能力有限,如有错误欢迎指正! :)