我有一个关于同时客户端调用 azure 移动服务功能的基本问题。 如何防止多个客户端/用户同时读取和更新变量和数据库表?
我想使用 AZURE 移动服务构建排行榜,对于客户端/游戏代码,我使用 Marmalade SDK。 我为该服务创建了一个名为“highscore”的数据库表,其中“track_id”是主键。 当我开始测试时,db 表是空的。
在客户端:
我从客户端向我的 AZURE 移动服务发出“HTTP post”调用 该调用包含“TrackId”和“Score”的数据。 我通过依次进行多次调用来模拟多个客户端。
伪代码:
- Http1.Post(trackId = 1, trackcore =100) -> "https://game_name.azure-mobile.net/api/test "
- Http2.Post(trackId = 1, trackcore =200) -> "https://game_name.azure-mobile.net/api/test "
- Http3.Post(trackId = 1, Trackscore =300) -> "https://game_name.azure-mobile.net/api/test "
- Http3.Post(trackId = 1, trackcore =400) -> "https://game_name.azure-mobile.net/api/test "
在 AZURE 移动服务代码中:
exports.post = function(request, response) {
var mssql = request.service.mssql;
var trackId = request.param('trackId');
var trackscore = request.param('trackscore');
var sql1 = "SELECT * FROM highscore WHERE track_id = '" + trackId + "'";
mssql.query(sql1, {
success: function(results) {
console.log("Length1:" + results.length + ", score:" + trackscore);
if (results.length == 0) {
console.log("Create new score" + ", score:" + trackscore);
var sql2 = "INSERT INTO highscore (track_id, track_score) VALUES ('" + trackId + "','" + trackScore + "')";
mssql.query(sql2);
} else if (results.length == 1) {
console.log("Update score" + ", score:" + trackscore);
var sql2 = "UPDATE highscore SET track_score = '" + trackScore + "' WHERE track_id = '" + trackId + "'";
mssql.query(sql2);
} else {
console.log('Error. Number of trackId: %s = %d', trackId, results.length);
}
mssql.query(sql1, {
success: function(results) {
console.log("Length2:" + results.length + ", score:" + trackscore);
}
});
},
error: function(err) {
console.log("Error:" + err);
response.send(statusCodes.OK, {
message: err
});
}
});
};
azure 日志:
服务的“LOGS”显示所有客户端调用同时在服务器功能内进行。当某些客户端线程尝试插入已存在的项目时,这会导致出现下面的“错误消息”。
1. Information Length2:1, score:400 api/test.js Thu Jan 29 2015, 21:37:03
2. Error {ERROR MESSAGE} api/test.js Thu Jan 29 2015, 21:37:03
3. Information Length2:1, score:400 api/test.js Thu Jan 29 2015, 21:37:03
4. Information Length2:1, score:200 api/test.js Thu Jan 29 2015, 21:37:03
5. Information Length2:1, score:300 api/test.js Thu Jan 29 2015, 21:37:03
6. Error {ERROR MESSAGE} api/test.js Thu Jan 29 2015, 21:37:03
7. Information Update score, score: 200 api/test.js Thu Jan 29 2015, 21:37:03
8. Information Length1:1, score: 200 api/test.js Thu Jan 29 2015, 21:37:03
9. Information Create new score, score: 100 api/test.js Thu Jan 29 2015, 21:37:03
10. Information Length1:0, score: 100 api/test.js Thu Jan 29 2015, 21:37:03
11. Information Create new score, score:400 api/test.js Thu Jan 29 2015, 21:37:03
12. Information Length1:0, score 400 api/test.js Thu Jan 29 2015, 21:37:03
13. Information Create new score, score:300 api/test.js Thu Jan 29 2015, 21:37:02
14. Information Length1:0, score:300 api/test.js Thu Jan 29 2015, 21:37:02
{ERROR MESSAGE} = "Error occurred executing query: Error: [Microsoft] [SQL Server Native Client 10.0]
[SQL Server]Violation of PRIMARY KEY constraint 'PrimaryKey_3e234221-4811-48a7-bc09-2dac9a666d37'.
Cannot insert duplicate key in object 'G.Highscore'. The duplicate key value is (1)."
问题
问题在于,不同的调用同时在服务器代码内部进行,从而以不可预测的顺序进行 SQL 查询、更新和读取变量。应该如何处理?
最佳答案
Azure 移动服务实现乐观并发,其方式是不使用“锁”来防止并发问题,而是允许客户端向服务发送更新,但如果另一个客户端有之前更新过相同的项目,那么最后一次更新将失败(并有适当的响应表明这一点)。如果客户端收到这样的“冲突”响应,那么它可以尝试处理冲突(例如,让服务器获胜,用新版本重新发送更新,表明它想要覆盖以前的更新,让用户选择等。 )。
This post谈论服务如何实现乐观并发。 This post展示了如何使用托管客户端 SDK 来使用该功能(在编写该功能时,尚不存在对其他客户端平台的支持,但后来它们已更新)。
关于multithreading - 将并发客户端调用同步到 azure 移动服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28192446/