我们在应用程序中使用下面的代码执行对数据库的写入。但是,可能有多个客户端在同一时间写入数据,因此我们使用了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(地图),用于将多个投票映射到唯一的用户ID; totalVotes(地图),用于跟踪总数投票和成员(列表),该列表是该组中所有用户ID的列表。 newVotes和totalVotes此时为空,成员包含几个ID(在这种情况下,两个唯一的Google ID) 该文档存在后,客户可以使用给定的代码进行投票。以我为例,我们都对同一个Google用户ID(例如:“ ID1”)进行了投票,并期望地图newVotes包含一个元素:{“ ID1”:2}。但是,我们俩都同时投票(没有抛出错误),并且newVotes字段包含{“ ID1”:1}。
答案 0 :(得分:0)
Transactions
不保证可以避免同时修改同一实体-除非进行序列化(或“读取更新锁定”)。它保证事务中的每个操作将在commit
时立即应用,或者如果tx为rolled back
要保证没有任何冲突,