Mongo写入安全机制
写入安全(Write Concern) 是一种客户端设置,用于控制写入的安全级别。默认况下,插入、删除和更新都会一直等待数据库响应(写入是否成功),然后才会继续执行。通常,遇到错误时,客户端会抛出一个异常(有些语言中可能不叫“异常”,不过实质上都是类似的东西)。
有一些选项可以用于精确控制需要应用程序等待的内容。两种最基本的写入安全机制是应答式写入(acknowledged wirte)和非应答式写入(unacknowledged write)。应答式写入是默认的方式:数据库会给出响应,告诉你写入操作是否成功执行。非应答式写入不返回任何响应,所以无法知道写入是否成功。
通常来说,应用程序应该使用应答式写入。但是,对于一些不是特别重要的数据 (比如日志或者是批量加载数据),你可能不愿意为了自己不关心的数据而等待数据库响应。在这种情况下,可以使用非应答式写入。
尽管非应答式写入不返回数据库错误,但是这不代表应用程序不需要做错误检查。如果尝试向已经关闭的套接字(socket)执行写入,或者写入套接字时发生了错误,都会引起异常。
使用非应答式写入时,一种经常被忽视的错误是插入无效数据。比如,如果试图插入两个具有相同"_id"字段的文档,shell就会抛出异常:
> db.foo.insert({"_id" : 1}) > db.foo.insert({"_id" : 1}) E11000 duplicate key error index: test.foo.$_id_dup key: { : 1.0 }
如果第二次插入时使用的是非应答式写入,那么第二次插入就不会抛出异常。键重复异常是一种非常常见的错误,还有其他很多类似的错误,比如无效的修改器或者是磁盘空间不足等。
shell与客户端程序对非应答式写入的实际支持并不一样:shell在执行非应答式写入 后,会检查最后一个操作是否成功,然后才会向用户输出提示信息。因此,如果在集合上执行了一系列无效操作,最后又执行了一个有效操作,shell并不会提示有错误发生。
> db.foo.insert({"_id" : 1}); db.foo.insert({"id" : 1}); db.foo.count() 1
可以调用get Last Error手动强制在shell中进行检查,这一操作会检查最后一次 操作中的错误。
> db.too.insert({"id" : 1}); db.foo.insert({"_id" : 1}); print( ... db.getLastError()); db.foo.count() E11000 duplicate key error index: test.foo.$_id_ dup key: { : 1.0 } 1
编写需要在shell中执行的脚本时,这是非常有用的。
注意:2012年,默认的写入安全机制改变了,所以,遗留代码的行为可能会与预期不一致。在此之前,默认的写入是非应答式的。
幸好,很容易得知当前代码是在默认的写入安全机制发生变化之前写的还是之后写的:默认的写入机制变为安全写入之后,所有驱动程序都开始使用MongoClient这个类。如果程序使用的连接对象是Mongo或者Connection或者其他内容,那么这段程序使用的就是旧的、默认不安全的API。在默认写入安全机制发生变化之前,任何语言都没有使用MongoClient作为类名,所以,如果你的代码使用了这个类名,说明你的代码是写入安全的。
如果使用的连接不是MongoCUent,应在必要时将旧代码中的非应答式写入改成应答式写入。