【发布时间】:2020-09-12 14:07:31
【问题描述】:
问题
我的概念是,当用户创建带有一些标签的帖子时,服务器首先检查标签名称是否已经存在,如果存在,它的计数器会增加,否则会创建一个新标签。
当多个用户同时创建一个带有新标签的帖子时,问题就出现了,比如说new_tag,然后多个同名标签会保留在数据库中,而不是 1 个标签,计数器 = # of users who used this标记
如您所见,每个用户都会在数据库中创建一个新的标签记录:
--------------------------------
| id | tagName | counter |
|------|-----------|-----------|
| 1 | new_tag | 1 |
| 2 | new_tag | 1 |
| 3 | new_tag | 1 |
| 4 | new_tag | 1 |
--------------------------------
我的期望:
--------------------------------
| id | tagName | counter |
|------|-----------|-----------|
| 1 | new_tag | 4 |
--------------------------------
这段代码展示了我是如何实现持久化的:
PostRepository
public async Task<bool> AddAsync(Post entity)
{
await AddNewTagsAsync(entity);
_context.Attach(entity.Event);
await _context.AddAsync(entity);
await _context.Database.BeginTransactionAsync();
var result = await _context.SaveChangesAsync();
_context.Database.CommitTransaction();
return result > 0;
}
public async Task AddNewTagsAsync(Post post)
{
// store tags name in lower case
if ((post.PostTags == null) || (post.PostTags.Count==0))
return;
post.PostTags.ForEach(pt => pt.Tag.TagName = pt.Tag.TagName.ToLower());
for(var i =0; i<post.PostTags.Count; i++)
{
var postTag = post.PostTags[i];
// here lays the main problem, when many concurrent users check for tag existence
// all get null and new tag will be created, workaround needed!
var existingTag = await _context.Tags.SingleOrDefaultAsync(x => x.TagName == postTag.Tag.TagName);
// if tag exists, increment counter
if (existingTag != null)
{
existingTag.Counter++;
postTag.Tag = existingTag;
continue;
}
// else the new Tag object will be peristed
}
}
【问题讨论】:
-
愚蠢的问题,但
PostTags条目的数量实际上不代表您正在寻找的计数器吗?但是,您可能想看看 EF 的锁定技术,例如Handling Concurrency Conflicts. -
在处理器时间中,
_context.Tags.SingleOrDefaultAsync...和CommitTransaction之间存在一个时代。这种类型的冲突只能通过唯一的数据库索引和捕获异常来解决。 -
@GertArnold 问题是,没有抛出异常。所有线程都看到这个标签不存在并创建它。
-
“所有线程都看到这个标签不存在”——这就是我的意思。他们有足够的时间得出这个结论。所以是的,索引是必要的,以使其最终安全。
-
我认为手动保持计数是不必要的,使用索引,通过 tagid 过滤的 PostTags 中的计数即使是数百万行也将花费可以忽略不计的时间。 TagName 上的唯一索引也可以避免重复。你应该只处理异常。
标签: c# postgresql entity-framework asp.net-core entity-framework-core