Уровень доступа к данным - статический список объектов и кеширование - PullRequest
2 голосов
/ 21 апреля 2010

Я делаю сайт, используя .net MVC

У меня есть слой доступа к данным, который в основном состоит из объектов статического списка, которые создаются из данных в моей базе данных.

Метод, который перестраивает эти данные, сначала очищает все объекты списка. Как только они опустеют, добавьте данные. Вот пример одного из списков, которые я использую. Это метод, который генерирует все почтовые индексы Великобритании. в моем приложении примерно 50 подобных методов, которые возвращают различную информацию, такую ​​как города, регионы, участники, электронные письма и т. д.

public static List<PostCode> AllPostCodes = new List<PostCode>();
  1. когда вызывается метод перестроения, он сначала очищает список.

    ListPostCodes.AllPostCodes.Clear ();

  2. затем он перестраивает данные, вызывая метод GetAllPostCodes ()

    /// <summary>
    /// static method that returns all the UK postcodes
    /// </summary>
    public static void GetAllPostCodes()
    {
        using (fab_dataContextDataContext db = new fab_dataContextDataContext())
        {
            IQueryable AllPostcodeData = from data in db.PostCodeTables select data;
    
            IDbCommand cmd = db.GetCommand(AllPostcodeData);
            SqlDataAdapter adapter = new SqlDataAdapter();
            adapter.SelectCommand = (SqlCommand)cmd;
            DataSet dataSet = new DataSet();
    
            cmd.Connection.Open();
            adapter.FillSchema(dataSet, SchemaType.Source);
            adapter.Fill(dataSet);
            cmd.Connection.Close();
    
            // crete the objects
            foreach (DataRow row in dataSet.Tables[0].Rows)
            {
                PostCode postcode = new PostCode();
                postcode.ID = Convert.ToInt32(row["PostcodeID"]);
                postcode.Outcode = row["OutCode"].ToString();
                postcode.Latitude = Convert.ToDouble(row["Latitude"]);
                postcode.Longitude = Convert.ToDouble(row["Longitude"]);
                postcode.TownID = Convert.ToInt32(row["TownID"]);
    
                AllPostCodes.Add(postcode);
                postcode = null;
            }
        }
    }
    

Перестройка происходит каждые 1 час. это гарантирует, что каждые 1 час на сайте будет свежий набор кэшированных данных.

Проблема, с которой я столкнулся, заключается в том, что иногда, если во время перестроения сервер будет поражен запросом и будет сгенерировано исключение. Исключение составляет «Индекс находился за пределами массива». это связано с тем, что список очищается.

ListPostCodes.AllPostCodes.Clear(); - // throws exception - although its not always in regard to this list.

Как только выбрасывается это исключение, приложение умирает. Я должен перезагрузить сервер, чтобы это исправить.

У меня есть 2 вопроса ...

  1. Если бы я использовал кэширование вместо статических объектов, это помогло бы?
  2. Можно ли как-то сказать "пока идет восстановление, дождитесь его завершения до принятия запросов"

любая помощь наиболее ценится;)

truegilly

Ответы [ 4 ]

1 голос
/ 21 апреля 2010

1 Если бы я использовал кэширование вместо статических объектов, это помогло бы?

Да, все, что вы делаете, легче сделать с помощью функции кэширования, встроенной в ASP.NET

Можно ли как-нибудь сказать "пока идет восстановление, дождаться его завершения, пока не будут приняты запросы"

Общий шаблон выглядит следующим образом:

  1. Вы запрашиваете данные со слоя данных

  2. Если Datlayer видит, что в кеше есть данные, то он обслуживает данные из кеша. Если нетданные находятся в кеше, данные запрашиваются из базы данных и помещаются в кеш.После этого он передается клиенту

Существуют правила (CacheDependency и Timeout), когда необходимо очистить кэш.

Самое простое решение - придерживаться этого шаблона: таким образом, первый запрос попадет в базу данных, а другие запросы будут обслуживаться из кэша.Вы запускаете обновление, внедряя SQLCacheDependency

0 голосов
/ 21 апреля 2010

В вашем случае вам необходимо обновлять данные каждый час.

1) ИТ-специалистам следует использовать кэш с абсолютным сроком действия, установленным на 1 час, поэтому он истекает через каждые 1 час. Проверьте кэш перед его использованием, выполнив проверку NULL. Если его значение NULL, получите данные из БД и заполните кэш.

2) При вышеуказанном подходе недостатком является то, что данные могут устареть на 1 час. Поэтому, если вы хотите постоянно обновлять данные, используйте SQLCacheDependency (PUSH). поэтому при каждом изменении в команде выбора, которую вы используете, кеш будет обновляться из базы данных с обновленными данными.

0 голосов
/ 21 апреля 2010

Я согласен с Томом, чтобы сделать эту работу, вам нужно будет выполнить синхронизацию. Единственное, что может повысить производительность, - это не очищать список, пока вы фактически не получите новые значения из базы данных:

// Modify your function to return a new list instead of filling the existing one.
public static List<PostCode> GetAllPostCodes()
{
    List<PostCode> temp = new List<PostCode>();
    ...
    return temp;
}

А когда вы перестраиваете данные:

List<PostCode> temp = GetAllPostCodes();
AllPostCodes = temp;

Это гарантирует, что ваш кэшированный список все еще действителен во время выполнения GetAllPostCodes (). Он также имеет то преимущество, что вы можете использовать список только для чтения, что немного упрощает синхронизацию.

0 голосов
/ 21 апреля 2010

Вы должны убедиться, что ваш список не изменен одним потоком, в то время как другие потоки пытаются его использовать. Это было бы проблемой, даже если вы использовали кэш ASP.NET, так как коллекции просто не являются потокобезопасными. Один из способов сделать это - использовать SynchronizedCollection вместо List. Затем убедитесь, что вы используете код, подобный следующему, при доступе к коллекции:

lock (synchronizedCollection.SyncRoot) {
    synchronizedCollection.Clear();
    etc...
}

Вам также придется использовать блокировку при чтении коллекции. Если вы перечисляете его, вы, вероятно, должны сделать копию перед тем, как сделать это, поскольку вы не хотите блокировать в течение длительного времени. Например:

List<whatever> tempCollection;
lock (synchrnonizedCollection.SyncRoot) {
    tempCollection = new List<whatever>(synchronizedCollection);
}
//use temp collection to access cached data

Другой вариант - создать класс ThreadSafeList, который использует внутреннюю блокировку, чтобы сделать сам объект списка поточно-ориентированным.

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