设为首页 收藏本站
查看: 993|回复: 0

[经验分享] MongoDB C# 驱动

[复制链接]

尚未签到

发表于 2015-7-6 07:48:43 | 显示全部楼层 |阅读模式
  http://www.mongodb.org/display/DOCS/CSharp+Driver+Tutorial#CSharpDriverTutorial-TheC%23Driver
  读书笔记
  C# Driver
  之前看了Bson类库,现在学习C# Driver
  Thread safety(多线程问题)
  只有少部分的C# Driver类是多线程安全的。比如MongoClient,MongoServer,MongoDatabase, MongoCollection 以及MongoGridFS。一般常用的类存在多线程问题,包括MongoCursor以及Bson类库中的所有类(除了其中的BsonSymbolTable是线程安全的)。
  所有的类的静态属性值和函数方法都不会引起多线程问题。
  MongoClient类
  这个类提供使用MongoDB server的基本对象。与MongoDB server服务进行链接的时候,client自动进行连接。(使用了连接池来进行更有效的连接)
  在连接一个副本集的时候,有且只用一个MongoClient实例。
  When you are connecting to a replica set you will still use only one instance of MongoClient, which represents the replica set as a whole. The driver automatically finds all the members of the replica set and identifies the current primary.
  这个类的实例不会引起多线程问题。
  除非其他设置,在默认设置情况下,所有操作需要一个WriteConcern,一个写入确定语句。另外,默认情况下,所有的写操作会锁定,直到server知道要进行写操作。
  Connection strings
  最简单的数据库连接是使用Connection string。标准的Connection string如下:
mongodb://[username:password@]hostname[:port][/[database][?options]]
  在使用认证的mongodb服务器上,username和password必须填写。
  port号码是可选的。默认的是27017.
  如果要连接多个服务器,可以直接填写多个服务器名(以及需要的端口号),并且以‘,’分割。如下:

mongodb://server1,server2:27017,server2:27018
  上面这段connection string 连接了三个数据库服务,由于多数据库服务是模糊不清的,不能分辨服务是否复本集,或者是多数据库服务。drive驱动会跳过connection string的语法检查,直接连接进数据库服务器,让server自己检查他们的类别。还有一些办法在连接的时候就指定数据服务器的类别,就是在connection string里面直接描述。如下:

mongodb://server1,server2:27017,server2:27018/?connect=replicaset
  可用的连接模式包括:automatic (默认), direct, replica set, 以及shardrouter。连接的规则如下:
  1、如果指定了某种连接模式,则直接使用否则使用默认的automatic。
  2、如果在connection string中有replica set name,则使用replica set模式
  3、如果connection string中仅有一个服务器,则使用direct模式
  4、另外,连接服务之后,服务决定连接的模式
  注意:如果有多服务器列表连接,其中有一个是复本集的一个,而其他不是,则连接模式将成为non-deterministic(未决定)。确定connection string中没有混合服务类型。
  当连接模式指定成为replica set,但是driver接口还是会找到primary服务器,即使该服务器不在connection连接列表中。直到connection列表中的一个服务器的回应(这个回应包括replica set以及现有的primary服务)。另外,即使在初始化语句完成之后,其他次级服务器也会被发现,并且自动加入到混合集群。这样,如果你有添加以及删除,移动replica set,driver接口会自己处理这些改变。
  顺便提到,假设你想要直接连接入一个replica set并且无论它是否是现在的primary(也许只是想监控下它的运行状态或者进行只读语句),可以使用下面连接语句:

mongodb://server2/?connect=direct;readpreference=nearest
  可以在下面的链接获取比较齐全的connection string文档
  http://www.mongodb.org/display/DOCS/Connections
  更加深入地额:
  http://docs.mongodb.org/manual/applications/replication/#replica-set-read-preference
  SSL Support
  这些不感兴趣,大概是driver连接的一个设置
  通过在connection string里面加入“ssl=true”选项来设置

mongodb://server2/?ssl=true
  在默认的情况下,server是通过本地的受信任的证书机构获取许可。在一些测试环境下面,测试server没有签署证书,为了缓解这个情况,可以使用在connection string里面添加“sslverifycertificate=false”来屏蔽所有certificate errors(认证错误)。
  Authentication
  MongoDB支持两种认证方式。一种是在程序执行时,调用特定的方法。在执行特定的方法时,认证将会被使用。另外一种健壮的方法是在MongoCredentialsStore存储认证信息。
  下面是一个例子,使用credential store来确定admin和“foo”数据库的认证信息。除了使用“admin”以及“foo”连接入数据库,还可以使用默认的认证“test”。

var url = new MongoUrl("mongodb://test:user@localhost:27017");
var settings = MongoClientSettings.FromUrl(url);
var adminCredentials = new MongoCredentials("admin", "user", true);
settings.CredentialsStore.Add("admin", adminCredentials);
var fooCredentials = new MongoCredentials("foo", "user", false);
settings.CredentialsStore.Add("foo", fooCredentials);
var client = new MongoClient(settings);
我感觉类似SQL语句:
GRANT ALL PRIVILEGES ON foo.* TO 'test'@'localhost' WITH GRANT OPTION;
GetServer method
在MongoClient实例中调用GetServer方法获取MongoServer的实例。

MongoServer class

  使用MongoServer类可以进行更多的控制操作。它使用了先进的技术通过一个单个的socket获取数据库以及进行一系列的数据库操作,并且保持数据库的一致性。
  GetDatabase method
  通过这个方法访问数据库
  例子代码:

MongoClient client = new MongoClient(); // connect to localhost
MongoServer server = client.GetServer();
MongoDatabase test = server.GetDatabase("test");
MongoCredentials credentials = new MongoCredentials("username", "password");
MongoDatabase salaries = server.GetDatabase("salaries", credentials);
  大多数的数据库设置从server对象中继承过来,并且提供了GetDatabase的重载。要override其他设置,可以调用CreateDataBaseSetting,在调用GetDataBase之前,改变设置。比如下面这样:

var databaseSettings = server.CreateDatabaseSettings("test");
databaseSettings.SlaveOk = true;
var database = server.GetDatabase(databaseSettings);
  GetDataBse会维持它返回的数据库实例,如果你再次调用这个函数,它会返回一个与之前完全一样的回来。
  RequestStart/RequestDone methods
  有些时候在系列操作执行的时候,为了保证正确的结果,需要在同一个connection上执行。但是这个是极少数的案例,在大多数情况下,没有必要调用RequestStart/RequestDone。使用RequestStart可以将写操作在同一个connection里面成操作列。直到server被要求执行时一起执行。
  在调用RequestStart和RequestDone的时候,系统将向线程池预约一个线程,如下:

using(server.RequestStart(database)) {
// 一系列的操作将在同一个connection中一起执行
}
这个database参数简单的表明了你的request要使用的数据库。
RequestStart在当前线程使用一个渐增的计数器,在任务完成时,计数器再递减。保留着的connection不会直接结束还给连接池,而是等到计数器递减至零。这个意味着RequestStart能够被嵌套地调用。
This means that calls to RequestStart can be nested and the right thing will happen.
注意:RequestStart返回一个IDisposable(接口)。如果你在使用RequestStart的时候不使用锁定块,RequestDone就必须调用来释放connection。

Other properties and methods
可以通过API文档来查看更加深入的属性和方法。

MongoDatabase class
这是一个描述MongoDB Server的类。通常情况下,一个database只有一个这个类的实例,除非你使用了不同的设置连接了相同的database。因为在这个情况下面,针对每个设置,都有一个实例。

这个类的实例不会产生多线程问题。

GetCollection method
这个方法返回的是一个database连接对象。当我们对这个collection对象发送请求时,我们也对这个collection做了默认的文档类型设置。比如:
MongoDatabase hr = server.GetDatabase("hr");
MongoCollection employees =
hr.GetCollection("employees");

一个collection不会限制成只有一个文档类型。默认的文档类型只是为了更加方便的使用这中文档类型。当你需要的时候,你完全可以定义不同的文档。
大多数的collection设置都是继承了collection对象,并且提供了GetCollection的多态性来方便你来重写一些常用的使用设置。要重写其他的设置,先调用CreateCollectionSetting来改变设置,然后再调用GetCollection方法。比如下面代码:
var collectionSettings = database.CreateCollectionSettings("test");
collectionSettings.SlaveOk = true;
var collection = database.GetCollection(collectionSettings);

GetCollection维持一个表的实例,如果你再次调用这个GetCollection,它会返回一样的内容。

Other properties and methods
查看api文档

MongoCollection class
这个类代表一个MongoDB database的collection。这个为这个collection定义了默认的文档。
这个类的实例不会造成多线程问题。

Insert method
插入函数。插入的对象可以是BsonDocument的实例对象,也可以是任何成功转换成BSON文档的类实例。例如:


MongoCollection books = database.GetCollection("books");
Book book = new Book {
Author = "Ernest Hemingway",
Title = "For Whom the Bell Tolls"
};
books.Insert(book);
  如果你要插入多重文档,InsertBatch要比Insert有效。
  FindOne以及FindOneAs方法
  要从collection中检索文档,可以使用这个方法。FindOne是最简单的。它会返回结果的第一个文档。例如:

MongoCollection books;
Book book = books.FindOne();
  如果你想检索一个文档,但是它不是类型的,你需要用到FindOneAs方法。它允许你返回你需要的文档类型。例如:

MongoCollection books;
BsonDocument document = books.FindOneAs();
  这个默认的类型是Book类型,但是我们返回的是BsonDocument类型的实例。
  Find以及FindAs方法
  Find和FindAs方法是用query语句来告诉服务器返回什么的文档。这个query(查询语句)的类型是IMongoQuery。IMongoQuery是一个标记接口,被类识别后可以用来作为查询语言。最常见的方法是,我们可以使用Query创建类或者是QueryDocument类来创建query语句。另外如果使用QueryWrapper封装任何类型query语句,query都可以被转变成BSON文档类型。
  使用QueryDocument

MongoCollection books;
var query = new QueryDocument("author", "Kurt Vonnegut");
foreach (BsonDocument book in books.Find(query)) {
// do something with book
}
  使用Query Builder

MongoCollection books;
var query = Query.EQ("author", "Kurt Vonnegut");
foreach (BsonDocument book in books.Find(query)) {
// do something with book
}
  使用其他任何类型,然后封装成query语句

MongoCollection books;
var query = Query.Wrap(new { author = "Kurt Vonnegut" });
foreach (BsonDocument book in books.Find(query)) {
// do something with book
}
  使用FindAs来获取非默认类型的返回文档

MongoCollection books;
var query = Query.EQ(b => b.Author, "Kurt Vonnegut");
foreach (Book book in books.FindAs(query)) {
// do something with book
}
  
  Save方法
  Save方法是Insert和Update的组合。如果文档的属性是有值的,它会成为Update,来对文档更新。否则将会创建一个新文档调用Insert方法。
  例如下面:纠正书的标题

MongoCollection books;
var query = Query.And(
Query.EQ("author", "Kurt Vonnegut"),
Query.EQ("title", "Cats Craddle")
);
BsonDocument book = books.FindOne(query);
if (book != null) {
book["title"] = "Cat's Cradle";
books.Save(book);
}
  TDocument必须要有个ID元素,否则你将调用Insert,将文档插入。
  Update方法
  用来更新文档。上面的Save代码可以一下面的方式重写

MongoCollection books;
var query = new QueryDocument {
{ "author", "Kurt Vonnegut" },
{ "title", "Cats Craddle" }
};
var update = new UpdateDocument {
{ "$set", new BsonDocument("title", "Cat's Cradle") }
};
BsonDocument updatedBook = books.Update(query, update);
或者使用Query和Update builders
MongoCollection books;
var query = Query.And(
Query.EQ("author", "Kurt Vonnegut"),
Query.EQ("title", "Cats Craddle")
);
var update = Update.Set("title", "Cat's Cradle");
BsonDocument updatedBook = books.Update(query, update);
FindAndModify方法
使用FindAndModify方法,你可以在一个原子操作里面查找一个匹配的文档并且修改更新.FindAndModify通常用于单个的文档,如果匹配了多个文档,可以使用标准的排序方法匹配到你自己想要修改的文档。
可以看下面文档使用FindAndModify
http://www.mongodb.org/display/DOCS/findAndModify+Command
调用FindAndModify的方法如下:
var jobs = database.GetCollection("jobs");
var query = Query.And(
Query.EQ("inprogress", false),
Query.EQ("name", "Biz report")
);
var sortBy = SortBy.Descending("priority");
var update = Update.
.Set("inprogress", true)
.Set("started", DateTime.UtcNow);
var result = jobs.FindAndModify(
query,
sortBy,
update,
true // return new document
);
var chosenJob = result.ModifiedDocument;
MapReduce方法
  Map/Reduce是一种从collection中聚合数据的方法。每个文档(或者使用选择query语句产生的是子集)被发送至map函数,map函数会产生一个中间的值。这个中间的值会传送至reduce函数进行数据的聚合。
下面的例子采集自MongoDB:The Definitive Guide(MongDB权威解析)的87页。它计算在collection中找到的每个key要被计算多少次

var map =
"function() {" +
"    for (var key in this) {" +
"        emit(key, { count : 1 });" +
"    }" +
"}";
var reduce =
"function(key, emits) {" +
"    total = 0;" +
"    for (var i in emits) {" +
"        total += emits.count;" +
"    }" +
"    return { count : total };" +
"}";
var mr = collection.MapReduce(map, reduce);
foreach (var document in mr.GetResults()) {
Console.WriteLine(document.ToJson());
}
  map/reduce是JavaScript程序
  深入了解看api文档
  
  MongoCursor类
  Find函数不会直接返回确切的查询结果。而是它返回一个游标来枚举检索查询结果。这个query查询语句实际上在你尝试检索第一个结果的时候才会送至服务器。这意味着,你可以通过控制游标检索结果来得到你感兴趣的内容。
  MongoCursor类的实例会造成多线程问题。至少在它被冻结之前不要使用。一旦它是冻结状态下,它就不会造成多线程安全问题。因为它是只读状态。
Enumerating a cursor检索游标
  使用C#中的foreach是最方便的检索方式

var query = Query.EQ("author", "Ernest Hemingway");
var cursor = books.Find(query);
foreach (var book in cursor) {
// do something with book
}
你也可以使用使用LINQ定义的方法来检索游标
var query = Query.EQ("author", "Ernest Hemingway");
var cursor = books.Find(query);
var firstBook = cursor.FirstOrDefault();
var lastBook = cursor.LastOrDefault();
Modifying a cursor before enumerating it在检索之前改变游标
1、直接修改游标的属性值
2、通过流畅的接口设置属性值
例如:我要跳过前100个结果,并且将显示结果限制在10个
var query = Query.EQ("status", "pending");
var cursor = tasks.Find(query);
cursor.Skip = 100;
cursor.Limit = 10;
foreach (var task in cursor) {
// do something with task
}
  或者使用流畅的接口

var query = Query.EQ("status", "pending");
foreach (var task in tasks.Find(query).SetSkip(100).SetLimit(10)) {
// do something with task
}
  Modifiable properties of a cursor

下面的属性值是可修改的

  • BatchSize (SetBatchSize)
  • Fields (SetFields)
  • Flags (SetFlags)
  • Limit (SetLimit)
  • Options (SetOption and SetOptions)
  • SerializationOptions (SetSerializationOptions)
  • Skip (SetSkip)
  • SlaveOk (SetSlaveOk)
  WriteConcern class
  WriteConcern 有很多等级,这个类就是用来描述这个等级的。WriteConcern 应用只用来操作那些没有返回的操作。比如Insert 、Save、Update和Remove。
  这个主要就是当Insert、Save、Update和Remove指令发送给服务器之后,会有一个GetLassError命令来确认这些操作是否成功执行了。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-83546-1-1.html 上篇帖子: 在Windows下快速部署MongoDB服务 下篇帖子: MongoDB 性能瓶颈分析 (转载)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表