繁体   English   中英

MongoDB 多步交易问题

[英]MongoDB multi step transaction problem

如果我们需要更新 CUSTOMER 文档并在同一事务中发送 email,那么确保以原子方式完成此操作的最佳方法是什么? 我们正在构建一个 ecomm 网站,我们需要此功能,因为当客户购买商品时,我们必须更新他们的订单历史记录并向他们发送 email 确认。 在使用 RDBMS 数据库的 Java 中,我们很容易做到这一点,只需更新数据库并发送包含 email 内容和详细信息的 JMS 消息; JDBC 和 JMS 都支持分布式事务,因此如果出现问题都可以回滚,但 MongoDB 则不然。 Mongo中有消息传递功能吗?

我们正在考虑在 Customer 的 orderHistory 嵌入文档中使用标志“emailSentFlag”。 下订单时,该标志设置为 false。 然后,我们将使用一个外部作业来扫描 emailSentFlag="false" 的所有订单历史记录,并在此时发送 email,但这使我们回到相同的情况,因为我们必须在发送后将标志设置回“true” email,这不是原子的。

> customer {
>     name:
>     email:
>     orderHistory{
>        orderId:
>        status:
>        emailSentFlag:

正如其他人所说,在 Mongo 中没有交易。

我建议您建立一个邮件队列,而不是设置一个标志,然后搜索整个集合。 我宁愿在邮件队列中放入一个条目,然后使用外部作业处理该队列。

至少这是我首先尝试的方式。 任何人,任何评论是好是坏?

您可以在 DOCUMENT 级别上执行原子操作: http://www.mongodb.org/display/DOCS/Atomic+Operations

我有一个用于排队您的电子邮件的集合,并在 email 文档中放置一个字段,以便在发送 email 时更新记录。 然后让您的发送作业在发送完成后更新父记录。

您甚至可以在客户文档中使用 email 文档中的 DB Ref。

值得考虑的是这些动作是否真的需要原子地发生:

  • 添加订单历史订单项
  • 发送确认 email

发送 email 的回滚标准是什么? email 地址无效? 无法连接到邮件服务器? Email 已发送但未收到? 您是否想因为邮件服务器停机而取消客户的交易?

我想说用customer.orderHistory.emailSentFlag创建一个新的订单行,然后安排一个计划作业来处理emailSentFlag = 0订单以发送确认电子邮件,然后在 email 成功发送后设置标志。

如果您收到反弹,或者由于某种原因交付失败,您可以随时重置标志并重试。 或者更好的是,将电子邮件工作分派到一个邮件队列系统,该系统为您处理所有这些事情。

它是一个无模式的数据库,因此请利用它:.-) 您可以使用鸭式输入,但可以将字段添加到跨类型识别的任何文档类型。 确保使用文档中未使用的名称。

在任何带有任务的文档(例如发送电子邮件)中添加一个tasks: []数组。 当您更新一个文档并且您需要有一个与之关联的“原子”事物时,会将任务推送到此队列。 例如,对于 email: { email: "cust@client.com", at: 0 } 后台进程轮询这些任务,将它们设置为将来到期,执行它们并删除它们。 如果某处发生故障,该任务将过期并重新运行。 因此,您可能会发送两封邮件,但这在邮件中或多或少是不可避免的,即使是交易也是如此。

您可以在 mongodb shell 中运行它:

#db.orders.remove()
db.orders.save( { name: "abc", tasks : [  { email: 'a@dom.com', at: 0}, { email: 'b@dom.com', at: 0} ] })
db.orders.save( { name: "def", tasks : [  { email: 'c@dom.com', at: 0}] })

now  = 10; future = 100; me = "some unique identifier for this scanning process"

while ( true ) {
  task = db.orders.findAndModify({
    query:   { "tasks.at": { $lt: now }},
    update : { $set : { "tasks.$.at": future, "tasks.$.who": me } }, 
    fields:  { "tasks":1},
    new:     true } )

  if ( !task)
    break;

  for ( var i in task.tasks ) {
    if ( task.tasks[i].who === me )
      print( "Send email " + task.tasks[i].email )  
  }

  db.orders.update( { _id: task._id }, { $pull: { tasks: { who: me } } } )
}

查看http://www.mongodb.org/display/DOCS/findAndModify+Command以获取类似示例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM