是否可以使用node.js和noSQL db进行事务处理?

是否可以使用node.js和noSQL db进行事务处理?,node.js,transactions,nosql,Node.js,Transactions,Nosql,我不是说真正的金钱交易 我正在做的项目是一个游戏,玩家之间交换东西。这基本上是一个交易过程,玩家a给玩家B 10格洛特换30头牛,你明白了 但是由于它是交互式的,而且同时有很多玩家,在一个聊天室式的环境中,所有的交易都是随机的,我想知道是否有可能用node.js做这样的事情,但是我看到了问题 我来自DB的背景,处理事务和回滚和提交的性质对于维护DB的健康状态是必要的。但是如果我们谈论的是node.js加上mongoDB(或者任何其他noSQL DB),那肯定是一种完全不同的心态,但我只是不明白它

我不是说真正的金钱交易

我正在做的项目是一个游戏,玩家之间交换东西。这基本上是一个交易过程,玩家a给玩家B 10格洛特换30头牛,你明白了

但是由于它是交互式的,而且同时有很多玩家,在一个聊天室式的环境中,所有的交易都是随机的,我想知道是否有可能用
node.js
做这样的事情,但是我看到了问题

我来自DB的背景,处理事务和
回滚
提交
的性质对于维护DB的健康状态是必要的。但是如果我们谈论的是
node.js
加上
mongoDB
(或者任何其他noSQL DB),那肯定是一种完全不同的心态,但我只是不明白它如何处理交易,即只涉及两方而不诉诸某种形式的锁定,但这肯定不是node的意义所在

我还没有找到任何东西,但这并不让我感到惊讶,因为
node.js
太新了

更新我知道交易的机制,尤其是银行风格的交易,但这不是一回事。我可能没有说清楚,但问题是玩家B正在向一个买家社区出售一些东西

这意味着,尽管玩家A在客户端启动了购买指令,但也有可能在同一时间,玩家C、D或E也点击购买同一头牛

现在,在正常事务中,预计至少第一个获得记录级表锁的人会在该时间点阻止其他方继续进行

然而,节点的使用性质,特别是它的速度、并发处理和用于显示实时数据库更新的特性,意味着我可以很容易地想象最慢的人(我们说的是毫秒)会获胜

例如,玩家A与玩家C同时发起购买。玩家A交易完成,Groat支付给玩家B,Cow在数据库中分配给玩家A。一毫秒后,奶牛被分配给玩家C


我希望这能更好地解释这个问题

这与Node.JS无关。Node.JS只连接到数据库,事务由数据库本身完成(除非您想在Node.JS中手动实现事务,这可能是一项有点困难的任务,但对于任何用任何语言编写的web服务器来说都是一样的)

您可以轻松地将MySQL与支持事务的Node.JS一起使用(例如)。因此,您要问的问题是:我可以与MongoDB进行交易吗?答案是:不,是的

不支持,因为MongoDB不支持开箱即用的事务


是的,因为您可以使用一些技巧来模拟事务。请参阅示例。

要使用文档数据库进行银行风格的交易,通常使用交易日志模式。在这种模式中,您可以将每个事务编写为自己的文档。您不维护每个帐户余额对应的文档。相反,您可以在查询时向上滚动事务文档,以给出当前余额


下面是一个适用于Couchbase map reduce的示例:

我正在开发一个名为node.js的oss应用程序级事务数据库

我们一开始就进行了全面的CRUD兵变,但很快意识到这相当困难。最好把它留给数据库。但有时您不想这样做,因为您希望能够切换数据库并保持代码的不可知性。然后我们简化为下一个最简单的部分——命名事务

所以,没有内置的回滚支持(您现在还必须自己做),但至少Waterline阻止您并发访问

在您的示例中(假设您使用的是express/connect/),它可能类似于:

function buyCow (req,res) {
   Cow.find(req.param('cowId'),function (err,cow) {
      if (err) return req.send(500,err);

      Cow.transaction('buy_cow',function (err, unlock) {
         if (err) { 
            // Notice how I unlock before each exit point?  REALLY important.
            // (would love to hear thoughts on an easier way to do this)
            unlock(); 
            return res.send(500,err); 
         }

         User.find(req.session.userId,function (err,user) {
            // If there's not enough cash, send an error
            if (user.money - cow.price < 0) { 
               unlock();
               return res.send(500,'Not enough cash!');
            }

            // Update the user's bank account
            User.update(user.id,{
               money: user.money - cow.price
            }, function (err,user) {
               if (err) { unlock(); return res.send(500,err); }

               Cow.update(cow.id, {owner: user.id}, function (err, cow) {
                  if (err) { unlock(); return res.send(500,err); }

                  // Success!
                  unlock();
                  res.json({success: true});
               });

            });
         });
      });

   });
}
函数buyCow(请求、回复){
Cow.find(请求参数('cowId'),函数(err,Cow){
如果(错误)返回请求发送(500,错误);
Cow.transaction('buy_Cow',函数(错误,解锁){
如果(错误){
//注意我如何在每个出口点之前解锁?非常重要。
//(想听听关于更简单方法的想法)
解锁();
返回res.send(500,err);
}
User.find(req.session.userId,函数(err,User){
//如果没有足够的现金,请发送错误消息
如果(user.money-cow.price<0){
解锁();
return res.send(500,'现金不足!');
}
//更新用户的银行帐户
User.update(User.id{
货币:user.money-cow.price
},函数(错误,用户){
if(err){unlock();返回res.send(500,err);}
update(Cow.id,{owner:user.id},函数(err,Cow){
if(err){unlock();返回res.send(500,err);}
//成功!
解锁();
res.json({success:true});
});
});
});
});
});
}

希望有帮助。我欢迎你的反馈(也许会提交?

这可能会很有趣,尽管我们采取了另一种方式来推进项目,因为自发布问题以来,关于这个主题的知识非常少。这很有意义——嗯,如果你想查看的话,我昨晚完成了waterline的第一个版本:它被设置为使用dirtydb,一个内存数据库。我的下一步行动将是创建一个mongodb适配器,然后mySQL(mySQL适配器将使用mySQL的内置事务)我知道现在是2018年,但是如果事务应该进行两次或更多更新,并且在第一次更新失败后进行一些更新,该怎么办?