Помощь среднего уровня - PullRequest
       13

Помощь среднего уровня

5 голосов
/ 22 января 2010

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

Я работаю над созданием промежуточного уровня в нашей текущей среде для компании, в которой я работаю. В настоящее время мы используем в основном .NET для программирования и создали собственные модели данных для всех наших различных систем баз данных (от Oracle, OpenLDAP, MSSQL и других).

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

Я пытаюсь максимально исключить объекты модели из приложения, чтобы при внесении изменений в базовую структуру базы данных мы могли легко редактировать и повторно развертывать промежуточный уровень, и нескольким приложениям не потребуется быть восстановлен. Я вкратце расскажу, в чем проблема в псевдокоде, поскольку это то, что лучше всего понимают разработчики:)

main
 {
  MidTierServices.UpdateCustomerName("testaccount", "John", "Smith");

  // since the data takes up to 4 seconds to be replicated from
  // write server to read server, the function below is going to
  // grab old data that does not contain the first name and last
  // name update....  John Smith will be overwritten w/ previous
  // data

  MidTierServices.UpdateCustomerPassword("testaccount", "jfjfjkeijfej");
 }

 MidTierServices
 {
  void UpdateCustomerName(string username, string first, string last)
  {
   Customer custObj = DataRepository.GetCustomer(username);

   /*******************
   validation checks and business logic go here...
   *******************/

   custObj.FirstName = first;
   custObj.LastName = last;

   DataRepository.Update(custObj);
  }

  void UpdateCustomerPassword(string username, string password)
  {
   // does not contain first and last updates
   Customer custObj = DataRepository.GetCustomer(username); 

   /*******************
   validation checks and business logic go here...
   *******************/

   custObj.Password = password;

   // overwrites changes made by other functions since data is stale
   DataRepository.Update(custObj); 
  }
 }

В дополнение к этому, варианты, которые я рассмотрел, - это создание собственного слоя кэширования, который занимает много времени и является очень сложной концепцией для продажи руководству. Используйте другой слой моделирования, который имеет встроенную поддержку кэширования, например, nHibernate: это также будет трудно продать руководству, потому что этот вариант также займет очень много времени, чтобы разорвать всю нашу пользовательскую модель и заменить ее на стороннее решение , Кроме того, не многие поставщики поддерживают наш большой массив баз данных. Например, .NET имеет LINQ to ActiveDirectory, но не LINQ to OpenLDAP.

В любом случае, извините за роман, но это скорее вопрос типа архитектуры предприятия, а не простой вопрос кода, такой как «Как получить текущую дату и время в .NET?»

Редактировать

Извините, я забыл добавить очень важную информацию в мой оригинальный пост. Я чувствую себя очень плохо, потому что Cheeso пережил много трудностей, чтобы написать очень подробный ответ, который бы исправил мою проблему, если бы не было больше проблемы (которую я тупо не включил).

Основная причина, по которой я сталкиваюсь с текущей проблемой, связана с репликацией данных. Первая функция выполняет запись на один сервер, а затем следующая функция выполняет чтение с другого сервера, который еще не получил реплицированные данные. По сути, мой код быстрее, чем процесс репликации данных.

Я мог бы решить эту проблему, всегда читая и записывая на один и тот же сервер LDAP, но мои администраторы, вероятно, убили бы меня за это. Специально настроить сервер, который используется только для записи, а затем 4 других сервера за балансировщиком нагрузки, которые используются только для чтения. Я никоим образом не администратор LDAP, поэтому я не знаю, является ли это стандартной процедурой.

1 Ответ

3 голосов
/ 22 января 2010

Вы описываете очень распространенную проблему.

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

Если это звучит как gobbledegook, это не так.Это довольно простая идея.Параллельная часть этого термина относится к тому факту, что с записанными данными происходят обновления, и эти обновления происходят одновременно.Возможно, много писателей.(Ваша ситуация - вырожденный случай, когда источником проблемы является один писатель, но это та же основная идея).Оптимистическая часть, о которой я расскажу через минуту.

Проблема

Возможно, что при наличии нескольких писателей часть чтения и записи в двух обновлениях чередуется,Предположим, у вас есть A и B, которые оба читают и затем обновляют одну и ту же строку в базе данных.A читает базу данных, затем B читает базу данных, затем B обновляет ее, затем A обновляет ее.Если у вас есть наивный подход, тогда «последняя запись» победит, и записи Б могут быть уничтожены.

Введите оптимистичный параллелизм.Основная идея состоит в том, чтобы предположить, что обновление будет работать, но проверьте.Вроде как доверяй, но проверяй подход к контролю над вооружениями несколько лет назад.Способ сделать это состоит в том, чтобы включить поле в таблицу базы данных, которое также должно быть включено в объект домена, которое обеспечивает способ отличить одну «версию» строки БД или объекта домена от другой.Простейшим является использование поля метки времени с именем lastUpdate, в котором хранится время последнего обновления.Существуют и другие, более сложные способы проверки согласованности, но поле метки времени подходит для иллюстрации.

Затем, когда писатель или средство обновления хочет обновить БД, он может обновлять только строку, для которой соответствует ключ (независимо от того, какой у вас ключ) , а также , когда совпадает lastUpdate.Это часть проверки.

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

SELECT ix, Created, LastUpdated, Headline, Dept FROM blogposts 
    WHERE CONVERT(Char(10),Created,102) = @targdate 

Этот тип запроса может извлечь все записи блога в базе данных за определенный день, месяц или что-то еще.

При простом оптимистическом параллелизме вы обновите одну строку , используя SQL следующим образом:

UPDATE blogposts Set Headline = @NewHeadline, LastUpdated = @NewLastUpdated
    WHERE ix=@ix AND LastUpdated = @PriorLastUpdated

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

Более строгое обновление может настаивать на том, что ни один из столбцов не был обновлен.В этом случае нет отметки времени вообще.Примерно так:

UPDATE Table1 Set Col1 = @NewCol1Value,
              Set Col2 = @NewCol2Value,
              Set Col3 = @NewCol3Value
WHERE Col1 = @OldCol1Value AND
      Col2 = @OldCol2Value AND
      Col3 = @OldCol3Value

Почему это называется «оптимистичным»?

OCC используется в качестве альтернативы удержанию блокировок базы данных, что является жесткимподход к сохранению данных.Блокировка БД может помешать любому читать или обновлять строку БД, пока она удерживается.Это, очевидно, имеет огромное значение для производительности.Таким образом, OCC смягчает это и действует «оптимистично», предполагая, что когда придет время обновлять, данные в таблице не будут обновлены за это время.Но, конечно, это не слепой оптимизм - вы должны проверить прямо перед обновлением.

Использование Optimistic Cancurrency на практике

Вы сказали, что используете .NET.Я не знаю, используете ли вы DataSets для доступа к данным, строго типизированные или нет.Но .NET DataSets, или, в частности, DataAdapters, включают встроенную поддержку OCC.Вы можете указать и вручную кодировать команду UpdateCommand для любого адаптера данных, и именно здесь вы можете вставить проверки согласованности.Это также возможно в среде разработки Visual Studio .

alt text
(источник: asp.net )

Если вы получите нарушение, обновление вернет результат, показывающий, что были обновлены нулевые строки. Вы можете проверить это в событии DataAdapter.RowUpdated . (Имейте в виду, что в модели ADO.NET есть разные DataAdapter для каждого вида базы данных. Ссылка есть для SqlDataAdapter, который работает с SQL Server, но вам потребуется другой DA для разных источников данных.)

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


Резюме

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


Другие ссылки:

...