文章点击数更新
对文章单击数的更新,考虑到并发的问题。
这里是通过队列的方式来进行解决。
1、模型修改
1 2 3 4 5 6 7 8 9 10 11
| public int ArticelClassId { get; set; }
public int ACount { get; set; } public ArticelClass? ArticelClass { get; set; }
|
修改ArticelInfo
模型。
同时对该模型的配置做一个简单的修改ArticelInfoConfig.cs
1 2 3
| builder.Property(x => x.Origin).HasMaxLength(100).IsRequired(); builder.Property(x => x.PhotoUrl).HasMaxLength(500).IsRequired(); builder.Property(x => x.ACount).HasDefaultValue(0);
|
重新执行数据迁移的操作
2、创建队列
在Cms.Common
项目中创建静态类QueueHelper.cs
该类中的代码如下: 分布式队列(Redis
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| namespace Cms.Common { public static class QueueHelper { private static ConcurrentQueue<int> _likeQueue = new ConcurrentQueue<int>();
public static void EnqueueLikeOperation(int articelId) { _likeQueue.Enqueue(articelId); }
public static bool DeEnquenuLikeOperation(out int articelId) { return _likeQueue.TryDequeue(out articelId!); } } }
|
3、入队操作
当打开某篇文章的详情页面的时候,就将所访问的文章的编号写入到队列中。
所以,我们需要在生成静态页面所用到的模版文件中,写ajax
代码,发送异步请求。
修改ArticelTemplateInfo.html
中的代码
1 2
| <link rel="stylesheet" type="text/css" href="/ArticelTemplate/ArticelStyle.css "> <script src="/js/axios.js"></script>
|
先导入axios
(注意路径是绝对路径)
1 2 3 4 5 6 7 8 9 10 11
| </html> <script type="text/javascript"> axios({ method: 'get', url: "/articelInfo/EditAcount?articelId=" + $data.id
}).then(({ data: res }) => { document.getElementById("acount").innerHTML = res.acount }) </script>
|
这样所生成的所有静态页面中都会有以上的代码
这里将所访问的文章的编号发送到服务端,然后服务端返回所访问的文章的点击数。
将所返回的单击数,更新到页面中
1 2 3 4 5
| <div class="artcelTop"><span>时间:2015/9/14 23:58:07 </span><span>信息来源:$data.Origin</span> <span id="acount">点击:$data.ACount</span> <span>【收藏此文】【字体:大 中 小】</span></div>
|
下面修改一下服务端的代码
修改ArticelInfoController.cs
控制器中的代码
1 2 3 4 5 6 7 8 9 10 11
| public async Task<IActionResult> EditAcount() { int articelId = Convert.ToInt32(Request.Query["articelId"]); var articelInfo = await articelInfoService.LoadEntities(a => a.Id == articelId).FirstOrDefaultAsync(); QueueHelper.EnqueueLikeOperation(articelId); return Json(new { StatusCode = 200, Acount = articelInfo!.ACount }); }
|
以上接收到所访问的文章编号以后,插入到队列中,同时查询一下所访问的文章以前数据库中存储的点击数,并且将其返回。
4、出队操作
问题:什么时候扫描队列呢?
在项目启动的时候就开启一个新的线程来扫描队列,所以修改Cms.Web/Program.cs
中的代码
如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| var app = builder.Build();
void StartProcessingQueue() { Task.Run(async () => { while (true) { int articleId = 0; if (QueueHelper.DeEnquenuLikeOperation(out articleId)) { MyDbContext dbContext = app.Services.GetService<MyDbContext>()!;
var articel = await dbContext.Articels.Where(a => a.Id == articleId).FirstOrDefaultAsync(); articel!.ACount = articel.ACount + 1; await dbContext.SaveChangesAsync();
} else { await Task.Delay(5000); } } }); }
StartProcessingQueue();
|
调用QueueHelper.DeEnquenuLikeOperation
方法,出队,获取对应的文章编号。
然后,这里直接根据从队列中获取的文章编号,查询数据库,更新点击数量。
这里由于业务比较简单,所以直接从容器中获取MyDbContext
的实例,然后更新数据库中的点击数量。