【问题标题】:Successively loading data into buffer依次将数据加载到缓冲区
【发布时间】:2020-05-07 06:58:25
【问题描述】:

我的数据需要很长时间才能从数据库加载,所以我要做的就是将其加载到本地内存并从那里使用它。有时我需要刷新它。

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;
    }
}

【问题讨论】:

    标签: c# mysql


    【解决方案1】:

    您需要从客户端/前端抽象出加载数据的细节。

    创建一个与您的客户交互的“存储库”,以便他们从这里请求数据。

    存储库可以 选项 1:

    • 在启动时加载所有数据。
    • 根据请求从内存中返回结果。
    • 在 xxx 分钟/小时后从 DB 刷新数据
    • 刷新期间
      • “旧”数据保留在内存中
      • 存储库构建了一个新的辅助数据集
      • 辅助数据完成后,存储库切换到新数据集 并丢弃旧的。 (您可以逐个表)

    选项 2:

    • 启动时,加载所有数据
    • 收到请求时
      • 如果请求存在于内存中,则返回它。否则对 DB 执行
      • 将 DB 结果存储在内存中以供将来的请求使用
      • 如果缓存数据 > xxx 分钟/小时,则将刷新安排为 后台进程

    但您无需重新发明轮子。有一些库可以帮助缓存,所以看看使用它们。一些如 Redis、Hazelcast 等也提供分布式缓存和所有你设置 TTL(生存时间)的到期时间,并为 C# 提供易于使用的 API/客户端库

    【讨论】:

      猜你喜欢
      • 2011-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-13
      • 1970-01-01
      • 2023-01-07
      • 1970-01-01
      相关资源
      最近更新 更多