c# - 依次将数据加载到缓冲区
问题描述
我有需要花费大量时间从数据库加载的数据,所以我所做的就是将其加载到本地内存并从那里使用它。有时我需要刷新它。
List<DataInMyMemory> data;
===============
data.add(LoadData(1)) // 4 sec
data.add(LoadData(2)) // 4 sec
data.add(LoadData(3)) // 4 sec
data.add(LoadData(4)) // 4 sec
Up 已经加载了列表中包含 4 个项目的数据(我有 200 多个项目,并且还会有更多)。当我重新加载时,我有两种方式:
data = new List<DataInMyMemory>();
===============
data.add(LoadData(1)) // 4 sec
data.add(LoadData(2)) // 4 sec
data.add(LoadData(3)) // 4 sec
data.add(LoadData(4)) // 4 sec
使用第一种方式,我需要清空当前数据并加载新数据。由于新的加载大约需要 20 分钟,如果有人尝试访问它,他们将得到 null,因为数据仍未加载。
然后我想出了另一个解决方案
List<DataInMyMemory> tempData = new List<DataInMemory>();
data.add(LoadData(1)) // 4 sec
data.add(LoadData(2)) // 4 sec
data.add(LoadData(3)) // 4 sec
data.add(LoadData(4)) // 4 sec
data = tempData;
这样数据将可用,但如果有人尝试从第一个用户(已加载但在临时列表中)获取数据,他将获得旧数据,我希望它尽可能相对。
那么有没有办法实现连续重新加载列表中的项目。
下来是完整的代码我是怎么做的:
for (int i = 0; i < TDShop.User.GetMaxID(); i++)
{
//VPCene is data list of type List<Tuple<int, List<WebShop.Cena>>>
VPCene.Add(new Tuple<int, List<WebShop.Cena>>(i + 1, TDShop.User.GetVPCene(i + 1)));
}
这是TDShop.User.GetVPCene()
需要 4 秒才能完成的功能(因为我加载 id 200+ 次,所以需要很多时间)
public static List<WebShop.Cena> GetVPCene(int UserID)
{
if (!AR.Initialized)
throw new Exception(AR.NotInitializedMessage);
try
{
List<WebShop.Cena> MaxCene = new List<WebShop.Cena>();
List<WebShop.Cena> MinCene = new List<WebShop.Cena>();
List<WebShop.Cena> CeneZaKorisnika = new List<WebShop.Cena>();
using (MySqlConnection con = new MySqlConnection(AR.ConnectionString))
{
con.Open();
List<Tuple<int, int>> NivoZaRobaID = new List<Tuple<int, int>>();
using (MySqlCommand cmd = new MySqlCommand(@"SELECT ROBA.ROBAID, USER_CENOVNIK.NIVO FROM USER_CENOVNIK
LEFT JOIN ROBA ON ROBA.CENOVNIK_GRUPAID = USER_CENOVNIK.CENOVNIK_GRUPAID
WHERE USER_CENOVNIK.USERID = @U ORDER BY ROBA.ROBAID ASC", con))
{
cmd.Parameters.AddWithValue("@U", UserID);
using (MySqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
if (dr[0] is DBNull)
{
continue;
}
NivoZaRobaID.Add(new Tuple<int, int>(Convert.ToInt32(dr[0]), dr[1] is DBNull ? 0 : Convert.ToInt32(dr[1])));
}
}
}
using (MySqlCommand cmd = new MySqlCommand("SELECT ROBAID, NABAVNACENA, PRODAJNACENA FROM ROBA", con))
{
using (MySqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
MinCene.Add(new WebShop.Cena(Convert.ToInt32(dr[0]), Convert.ToDouble(dr[1])));
MaxCene.Add(new WebShop.Cena(Convert.ToInt32(dr[0]), Convert.ToDouble(dr[2])));
if (!NivoZaRobaID.Exists(x => x.Item1 == Convert.ToInt32(dr[0])))
NivoZaRobaID.Add(new Tuple<int, int>(Convert.ToInt32(dr[0]), (int)CenovnikKlasa.Iron));
}
}
}
foreach (Tuple<int, int> n in NivoZaRobaID)
{
double minCena = MinCene.Where(x => x.RobaID == n.Item1).FirstOrDefault().VPCena;
double maxCena = MaxCene.Where(x => x.RobaID == n.Item1).FirstOrDefault().VPCena;
double razlika = (maxCena - minCena) * (1 - OD_UKUPNE_RAZLIKE_NAMA_OSTAJE_SIGURNIH);
double namaOstaje = razlika;
double K = razlika / (Cenovnik.nLevel - 1) * NivoZaRobaID.Where(x => x.Item1 == n.Item1).FirstOrDefault().Item2;
if (minCena <= 0 || maxCena <= 0)
CeneZaKorisnika.Add(new WebShop.Cena(n.Item1, -9999));
else
CeneZaKorisnika.Add(new WebShop.Cena(n.Item1, maxCena - K));
}
return CeneZaKorisnika;
}
}
catch (Exception ex)
{
throw ex;
}
}
解决方案
您需要从客户端/前端抽象加载数据的细节。
创建一个与您的客户交互的“存储库”,以便他们从这里请求数据。
存储库可以是选项 1:
- 启动时加载所有数据。
- 根据请求从内存中返回结果。
- 在 xxx 分钟/小时后从数据库刷新数据
- 刷新期间
- “旧”数据保留在内存中
- 存储库建立了一个新的辅助数据集
- 辅助数据完成后,存储库切换到新数据集并删除旧数据集。(您可以逐表执行此表)
选项 2:
- 启动时,加载所有数据
- 当它收到请求时
- 如果请求存在于内存中,则返回它。否则对数据库执行
- 将数据库结果存储在内存中以供将来请求
- 如果缓存数据 > xxx 分钟/小时,则将刷新安排为后台进程
但是你不需要重新发明轮子。有一些库可以帮助缓存,所以看看使用它们。一些如 Redis、Hazelcast 等也提供分布式缓存和所有你设置 TTL(生存时间)的到期时间,并为 C# 提供易于使用的 API/客户端库
推荐阅读
- java - 如何使用 API Gateway 代理在 AWS Lambda 中将多个文件作为多部分请求处理?
- excel - VBA 运行时错误 76 - 在 Excel 中找不到路径
- amazon-web-services - 使用 CloudFormation 模板在 Amazon S3 Glacier 中创建文件库
- javascript - 在 Gitlab Servicedesk 功能中将收集的电子邮件作为新票证/问题发送
- php - 评级值始终插入为 1
- python - Django中OAuth1.0a的验证POST请求
- python - 在 python 中使 Eratosthenes 的筛子更有效率?
- c# - ASP.NET Core 单元测试在测试控制器问题响应时抛出 Null Exception
- ansible - 错误消息中存在字符串时忽略失败
- php - Facebook集成:如何实现非规范元数据抓取