Вопрос

У меня проблема в следующем:

У меня есть таблица (просто пример) со следующими полями:

ID int
Value int

У меня есть метод увеличенияByFive(), который делает следующее:

method IncreaseByFive(int ID)
{    
    int value = GetValueFromDB(ID);
    value = value + 5;
    SaveValueToDB(value, ID);    
}

Чего я хочу избежать, так это следующей ситуации:

  1. Пользователь А вызывает метод и получает значение (в настоящее время 5).
  2. Пользователь Б вызывает метод и получает значение (в настоящее время 5)
  3. Пользователь А увеличивает значение на 5 (теперь 10)
  4. Пользователь Б увеличивает значение на 5 (теперь 10)
  5. Пользователь А сохраняет значение (10)
  6. Пользователь Б сохраняет значение (10)

Теперь запись имеет значение 10, хотя должно было быть 15.

Я хочу заставить следующее:

  1. Пользователь А вызывает метод и получает значение (в настоящее время 5).
  2. Пользователь Б вызывает метод, но ему приходится ждать, потому что А уже вызвал его.(Бабки!)
  3. Пользователь А увеличивает значение (теперь 10)
  4. Пользователь Б все еще ждет
  5. Пользователь А сохраняет значение (запись имеет значение 10)
  6. Пользователь B теперь может прочитать значение (10).
  7. Пользователь Б увеличивает значение (15)
  8. Пользователь Б сохраняет значение

Теперь запись имеет значение 15, и это именно тот результат, который я ищу.

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

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

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

Я разрабатываю этот проект с помощью C# (3.5) и SQL Server 2008.

Что думает коллективный разум?

Это было полезно?

Решение

Может быть, я надобдумывая это, но не могли бы вы просто обернуть весь логический блок?..

  • прочитать значение
  • записать значение

в транзакции базы данных соответствующий уровень?

SET TRANSACTION ISOLATION LEVEL
    { READ UNCOMMITTED
    | READ COMMITTED
    | REPEATABLE READ
    | SNAPSHOT
    | SERIALIZABLE
    }
[ ; ]
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top