5

我不是在谈论真钱交易

我正在做的项目是一个玩家互相交换东西的游戏。这基本上是一个交易过程,玩家 A 给玩家 B 10 块钱以换取 30 头奶牛,你明白了。

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

我来自数据库背景,处理事务及其性质rollbackcommit维护数据库健康状态所必需的。但是,如果我们谈论的是node.jsplus mongoDB(或任何其他 noSQL DB),那肯定是一种完全不同的心态,但我只是不明白它如何处理交易,因为只有两方应该参与而不诉诸某种形式的锁定,但肯定不是这样node

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

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

这意味着尽管玩家 A 在客户端发起了购买指令,但也有可能大约在同一时间,玩家 CD 或 E 也点击购买同一头牛。

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

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

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

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

4

3 回答 3

4

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

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

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

是的,因为您可以使用一些技巧来模拟交易。例如见这篇文章

于 2012-07-25T16:41:02.280 回答
2

要使用文档数据库进行银行式事务,通常使用事务日志模式。在这种模式中,您会将每个事务编写为它自己的文档。您不维护与每个帐户余额相对应的文档。相反,您在查询时卷起交易文档,以提供当前余额。

这是一个适用于 Couchbase 地图缩减的示例:http: //guide.couchdb.org/draft/recipes.html

于 2012-08-07T22:31:30.687 回答
2

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

我们从全面的 CRUD 静音开始,但很快意识到这非常困难。最好把它留给数据库。但有时你不想——因为你希望能够切换数据库并保持你的代码不可知。因此,我们简化为下一个最简单的部分——命名事务。

所以,没有内置的回滚支持(你现在仍然需要自己做),但至少 Waterline 可以防止你的并发访问。

在您的示例中(假设您在 express/connect/ Sails中),它可能看起来像:

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});
               });

            });
         });
      });

   });
}

希望有帮助。我欢迎您的反馈(也许还有提交?)

于 2012-12-26T18:04:30.750 回答