如果不满足特定的属性组合,是否可以安全地添加对象,如果对象已经在数据库中,是否可以更新现有的对象?
我当前的代码如下所示,但这对于多用户访问来说并不安全(可能会导致从数据库阅读到写回之间的时间重复创建组合):
var databaseTopic = await _context.DataTopics
.Where(dt => dt.Name == name
&& dt.Unit == dataTopicUnit)
.FirstOrDefaultAsync().ConfigureAwait(false);
if (databaseTopic == default)
{
databaseTopic = new DataTopic()
{
Name = name,
Unit = dataTopicUnit,
};
_context.DataTopics.Add(databaseTopic);
}
databaseTopic.ValueKind = valueKind;
await _context.SaveChangesAsync().ConfigureAwait(false);
如您所见,我基于Name
和Unit
获取dataTopic,如果不存在该条件,则创建一个新的dataTopic,但始终更新ValueKind
,无论它是新的DataTopic
还是现有的dataTopic。软件不仅要支持多用户,还要支持多业务,多个软件示例可以访问同一个数据库。
现在(开发时间),我添加了一个SemaphoreSlim
以防止多个用户添加相同的DataTopic
:
await _sharedValues.CreateDataTopicGate.WaitAsync().ConfigureAwait(false);
//Do all the DataTopic update and add stuff
_sharedValues.CreateDataTopicGate.Release();
1条答案
按热度按时间ztmd8pv51#
基本上,安全地实现这一点的唯一方法是使您的数据库成为所有重复请求的处理程序。
1:确保对构成主键的字段有唯一约束,这样在所述字段上永远不会有重复。
2:阅读本指南:https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-upsert/使其适应您代码。
3:利润。
我理解你想用信号量做什么,但是如果你想从一个特定的输入组件控制它,你真正需要的是在你的输入提供器上实现一个分区键,这意味着你有活动的写数据库的每个线程,将只允许一个特定的键-〉进入一个特定的线程,确保你不能陷入争用状态,因为一个唯一的键,将由唯一地处理该唯一密钥的线程串行地处理。
然而,这伴随着警告,输入现在只能通过这个输入提供程序到达。这是一个可怕的设置。
任何其他UI、设备或源都不能直接写入postgres数据库,因为它会绕过分区密钥。