Последовательная загрузка данных в буфер - PullRequest
0 голосов
/ 06 мая 2020

У меня есть данные, загрузка которых из базы данных занимает много времени, поэтому я загружаю их в локальную память и использую оттуда. Время от времени мне нужно обновлять sh it.

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 минут, если кто-то попытается получить к нему доступ, он получит нулевое значение, поскольку данные все еще не загружены.

Затем я придумал другое решение, которое:

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;

таким образом данные будут доступны, но если кто-то попытается получить данные от первого пользователя (который уже загружен, но находится в временном списке), он получит старые данные, и я хочу, чтобы они были как можно более относительными.

Так есть способ добиться последовательной перезагрузки элементов в списке.

Down - это полный код, как я это делаю:

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 секунды sh (так как я загружаю 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 Ответ

0 голосов
/ 06 мая 2020

Вам нужно абстрагироваться от деталей загрузки данных от вашего клиента / внешнего интерфейса.

Создайте «Репозиторий», с которым ваш клиент взаимодействует, чтобы они запрашивали данные отсюда.

Репозиторий может либо Вариант 1:

  • При запуске загрузить все данные.
  • По запросу вернуть результат из памяти.
  • Через xxx минут / часов refre sh данные из БД
  • Во время обновления
    • «старые» данные остаются в памяти
    • Репозиторий создает новый вторичный набор данных
    • Когда вторичные данные заполнены, репозиторий переключается на новый набор данных и удаляет старый. (Вы можете сделать эту таблицу по таблице)

Вариант 2:

  • При запуске загрузить все данные
  • При получении запроса
    • Если запрос существует в памяти, вернуть его. В противном случае выполнить против БД
    • Сохранить результат БД в памяти для будущих запросов
    • Если объем кэшированных данных> xxx минут / часов, запланировать обновление sh как фоновый процесс

Но изобретать велосипед не нужно. Существуют библиотеки, которые помогают с кешированием, так что посмотрите на их использование. Некоторые, такие как Redis, Hazelcast и др. c. также предлагают распределенное кэширование и все, что вам нужно, чтобы установить TTL (время жизни) для истечения срока, и предлагают простые в использовании API / клиентские библиотеки для C#

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...