Node.JS + Socket.io + MySql:查询callback仅调用2次

我正在使用socket.io mysql模块在node.js上实现一个聊天系统:

client.on('message', function (data) { if (!channel) { console.error('Cannot send message: no channel created'); return; } console.log('message received'); channel.addMessage(data.conversationID, data.text); }); 

通道是实现消息传递逻辑的对象。 addMessage如下:

 addMessage: function (conversationID, text) { var that = this; // Inner function that inserts a message record in the database and optionally notifies // the other connected client var insertMessageIn = function(conversation) { ... }; // If a conversation is already open, uses its reference directly. Otherwise, performs a select query and adds the // result to the set of open conversations this.open(conversationID, function (conversation) { if (that.senderUserID != conversation.StarterUserID || conversation.TotalMessages > 2 * that.MAX_UNANSWERED_MESSAGES) { insertMessageIn(conversation); return; } console.log('counting total messages'); // Prevents an user to importunate another one by continuously sending messages. At most 5 messages can // be sent without a reply that.lockAndQuery('messages', 'SELECT TotalMessages FROM conversations WHERE ID = ?', [conversation.ID], function (error, rows) { if (error) { console.error('Cannot read total messages ' + error.stack); return; } var totalMessages = rows[0].TotalMessages; conversation.TotalMessages = totalMessages; console.log('total messages ' + totalMessages); if (that.senderUserID == conversation.StarterUserID && totalMessages >= that.MAX_UNANSWERED_MESSAGES && totalMessages < 2 * that.MAX_UNANSWERED_MESSAGES) { var rawQuery = 'SELECT COUNT(*) AS ReplyMessageCount FROM messages WHERE ConversationID = ? AND SenderUserID = ?'; var params = [conversation.ID, conversation.TargetUserID]; that.chatHandler.dbConnection.query(rawQuery, params, function (error, rows) { if (error) { console.error('Cannot count messages ' + error.stack); return; } var count = rows[0].ReplyMessageCount; // If count is gt 0, the receiver has replied at least one: you can keep messaging normally if (count > 0) insertMessageIn(conversation); else that.clientSocket.emit('too many messages without answer', null); }); } else { insertMessageIn(conversation); } }); }); } 

这可以防止用户开始一个会话,用其他用户发送消息。 lockAndQuery方法是为了防止死锁,并执行如下:

 lockAndQuery: function (tableName, query, params, callback) { var that = this; this.chatHandler.dbConnection.query('LOCK TABLES ' + tableName + ' WRITE', function (error, result) { if (error) { console.error('Cannot acquire lock ' + error.stack); return; } that.chatHandler.dbConnection.query(query, params, function (e, r) { callback(e, r); that.chatHandler.dbConnection.query('UNLOCK TABLES'); }); }); } 

您可能会注意到,尽pipeselect是在桌面对话上,locking在桌面消息上。 这是需要的,因为在消息上触发更新对话字段。

问题是以下。 在我的testing页面中,我有一个发送6条消息到服务器的循环。 由于与使用的ID的对话已经打开并且有一些消息,所有这些都应该被服务器拒绝。 特别是,我期望在服务器上看到的日志信息的顺序是:

 message received counting total messages total messages 5 

重复了6次。 但是这不是我得到的。 实际产出是:

 message received counting total messages total messages 5 message received counting total messages message received counting total messages total messages 5 message received counting total messages message received counting total messages total messages 5 message received counting total messages 

正如你所看到的,代码只能在一半的时间内访问查询callback,而不会引发任何错误。 为什么?