代码:
public func emailExists(email: String, exists: @escaping ((Bool) -> Void)) {
let safeEmail = DatabaseManager.safeEmail(emailAddress: email)
database.child(safeEmail).runTransactionBlock ({ (currentData: MutableData) -> TransactionResult in
guard currentData.value as? [String: Any] != nil else {
print(" Email doesn't exist")
database.child(safeEmail).setValue([ *SomeData* ])
exists(false)
return TransactionResult.success(withValue: currentData)
}
exists(true)
return TransactionResult.success(withValue: currentData)
})
}
如果我在主父节点上运行TransactionBlock,这会锁定整个数据库,直到事务完成(或不完成)?如果多个用户同时调用此函数,那么实现此功能会是个坏主意吗?
Firebase实时数据库中的事务并不是真正锁定节点,而是比较和设置操作。
当您在节点上运行事务时,客户端会调用您的回调,并使用其对该节点值的当前猜测(通常是第一次null
)。然后告诉它整个节点的新值应该变成什么。
客户端将这两个值(当前值和新值)发送到服务器,服务器检查当前值是否与客户端猜测的值相同。如果它是相同的,它会将结果写入数据库。如果它不相同(通常不会是第一次),它会告诉客户端写入被拒绝,并为其提供数据库中节点的实际值。然后,客户端使用当前值的更新猜测来调用回调。
这种情况一直重复,直到服务器能够提交新值(因为当前值未修改),或者直到尝试次数用完。
在数据库节点中运行更高级别的事务意味着:
- 您正在从数据库中请求更多数据
- 对数据进行冲突写入(称为争用)的可能性更大
建议在数据库中尽可能低地运行事务,实际上,将数据移动/复制到更低的数据库中以实现这一点是很常见的。
在JSON结构中运行过高的事务可能会导致争用问题,这种情况通常只有在系统上有足够的并发用户时才会发生,因此最好尽早防止这种情况发生。