【发布时间】:2019-08-31 17:38:13
【问题描述】:
我们在应用程序中使用下面的代码来执行对数据库的写入。但是,多个客户端可能同时在写入,所以我们使用了Transaction,因为如果在执行期间数据被另一个Transaction 修改,它应该会再次运行。
不过似乎出了点问题:当单独的客户端(两个不同的移动设备)同时运行下面的代码时,似乎只有一个客户端更新了数据库中的值。
这可能是什么原因造成的,我们将来如何防止这种情况发生?
static Future< bool > voteOnUser(GroupData groupData, String voteeID) async {
await Firestore.instance.runTransaction((Transaction transaction) async {
DocumentReference groupRef = Firestore.instance
.collection("groups")
.document( groupData.getGroupCode() );
DocumentSnapshot ds = await transaction.get( groupRef );
/// Initialize lists
Map<dynamic, dynamic> dbData = ds.data['newVotes'];
Map<String, int> convertedData = new Map<String, int>();
/// Loop the database Map and add the values to the data Map
/// All data is assumed to exist and definitely be of the desired types
dbData.forEach( (key, value) {
convertedData[key.toString()] = value;
} );
if (convertedData.containsKey( voteeID ))
convertedData[voteeID] += 1;
else convertedData[voteeID] = 1;
Map<String, dynamic> incremented = new Map<String, dynamic>();
incremented['newVotes'] = convertedData;
await transaction.update(groupRef, incremented);
});
return true;
}
编辑:此代码的目的是对位于文档内地图中的用户进行投票。多个客户端可以同时投票,每次投票应该将地图中一个元素的值加一。 当两个客户端同时对例如之前没有投票的 ID 为“joe”的用户进行投票时,预期的结果是 joe 将获得两票。但是,在测试同时投票时,我们观察到数据库中只添加了一票,而不是期望的两票。
编辑 2:首先,该文档存在并且包含一个空映射 newVotes。我们正在使用两种不同的移动设备进行测试,并在±同一时间点投票。几乎立刻,文档就被更新了,并且一个用户 ID 被添加到之前为空的映射中,只需一票,而我们预计两票会映射到该键。
编辑 3:首先,创建一个包含以下字段的文档:newVotes (map) 将投票数映射到唯一的用户 id,totalVotes (map) 跟踪总数投票和成员(列表),这是该组中所有用户 ID 的列表。 newVotes 和 totalVotes 此时为空,且 members 包含一些 ID(在本例中,是两个唯一的 Google ID) 一旦此文档存在,客户就可以使用给定的代码进行投票。在我的例子中,我们都对同一个谷歌用户 ID(比如:“ID1”)进行了投票,并希望地图 newVotes 包含一个元素:{“ID1”:2}。但是,我们同时投票(没有引发错误),并且 newVotes 字段包含 {"ID1":1}。
【问题讨论】:
-
请编辑问题以准确解释您所观察到的不符合您预期的情况。
-
我编辑了这个问题,希望这次我把我的问题说清楚了。
-
你能说得更具体点吗?在执行代码之前,文档究竟包含什么?后面包含什么?这与预期的内容有何不同?
-
我添加了另一个编辑,应该澄清一些事情。
-
1) 您是否锁定了该实体以读取显性? 2) Optimistic lockig (version controll) 就是你要找的。span>
标签: firebase dart google-cloud-firestore