Rails MongoDB,如何获取最后插入的文档并确保它是线程安全的?
当我在集合 X 中添加新文档时,我需要获取在同一集合中插入的最后一个文档,因为该文档的某些值必须影响我当前插入的文档。
基本上作为一个简单的例子,我需要这样做:
class X
include Mongoid::Document
include Mongoid::Timestamps
before_save :set_sum
def set_sum
self.sum = X.last.sum + self.misc
end
field :sum, :type => Integer
field :misc, :type => Integer
end
如果存在并发插入,如何确保该类型的进程永远不会中断?我必须确保当计算 self.sum = X.last.sum + self.misc
时,X.last.sum
绝对代表插入到的最后一个可能的文档收藏 ?
这对我的系统至关重要。它需要是线程安全的。
Alex
ps:这也需要高性能,当集合中有 50k 文档时,不可能花费时间来获取最后一个值......
I need when I add a new document in my collection X to get the last document that was inserted in that same collection, because some values of that document must influence the document I am currently inserting.
Basically as a simple example I would need to do that:
class X
include Mongoid::Document
include Mongoid::Timestamps
before_save :set_sum
def set_sum
self.sum = X.last.sum + self.misc
end
field :sum, :type => Integer
field :misc, :type => Integer
end
How can I make sure that type of process will never break if there are concurrent insert? I must make sure that when self.sum = X.last.sum + self.misc
is calculate that X.last.sum
absolutely represents that last possible document inserted in the collection ?
This is critical to my system. It needs to be thread safe.
Alex
ps: this also needs to be performant, when there are 50k documents in the collections, it can't take time to get the last value...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这种行为相当于有一个自动递增的id。
http://www.mongodb.org/display /DOCS/如何+创建+自动+增量+字段
最简洁的方法是拥有一个辅助集合,其中包含一个(或多个)代表当前总值的文档。
然后在您的客户端中,在插入新文档之前,执行 findAndModify() 来自动更新总计并检索当前的总计文档。
当前文档的一部分可以是自动递增的_id,这样即使有并发插入,只要按_id排序,你的文档就会正确排序。
唯一需要注意的是:如果您的客户端应用程序在 findAndModify 之后和插入之前死掉,那么您将在其中出现间隙。
要么没关系,要么您需要添加额外的保护措施,例如保留辅助日志。
如果你想 100% 安全,你也可以从两阶段提交中获得灵感
http://www.mongodb.org/display/DOCS/two-phase+commit
基本上,这是与跨越 1 个以上服务器的任何数据库进行事务处理的正确方法(甚至 sql 也无济于事)
最好的
股份公司
this kind of behavior is equivalent to having an auto increment id.
http://www.mongodb.org/display/DOCS/How+to+Make+an+Auto+Incrementing+Field
The cleanest way is to have a side collection with one (or more) docs representing the current total values.
Then in your client, before inserting the new doc, do a findAndModify() that atomically updates the totals AND retrieves the current total doc.
Part of the current doc can be an auto increment _id, so that even if there are concurrent inserts, your document will then be correctly ordered as long as you sort by _id.
Only caveat: if your client app dies after findAndModify and before insert, you will have a gap in there.
Either that's ok or you need to add extra protections like keeping a side log.
If you want to be 100% safe you can also get inspiration from 2-phase commit
http://www.mongodb.org/display/DOCS/two-phase+commit
Basically it is the proper way to do transaction with any db that spans more than 1 server (even sql wouldnt help there)
best
AG
如果您需要保留运行总和,则可能应该在不同集合中的另一个文档上完成此操作。保持此运行总和的最佳方法是使用
$inc
原子操作。在计算这个总和时实际上不需要执行任何读取。您需要将 X 文档插入到其集合中,然后还要将
$inc
插入到另一个文档中,该值用于保存来自的所有misc
值的计数X 文档。注意:这仍然不是事务性的,因为您要分别更新两个不同集合中的两个文档,但它将具有高性能且完全线程安全。
有关更多信息,请查看所有 MongoDB 原子操作。
If you need to keep a running sum, this should probably be done on another document in a different collection. The best way to keep this running sum is to use the
$inc
atomic operation. There's really no need to perform any reads while calculating this sum.You'll want to insert your X document into its collection, then also
$inc
a value on a different document that is meant for keeping this tally of all themisc
values from the X documents.Note: This still won't be transactional, because you're updating two documents in two different collections separately, but it will be highly performant, and fully thread safe.
Fore more info, check out all the MongoDB Atomic Operations.