Как справиться с этой проблемой параллелизма данных? - PullRequest
1 голос
/ 20 июля 2011

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

Предположим, есть учетная запись ABC, в которой 500 долларов.Пользователь из Интернета может перевести эти средства на другие счета.Это будет включать 2 этапа: 1-я проверка доступности средств и 2-й перевод.Я делаю транзакцию и выполняю в ней оба действия.

Проблема в том, что за время (скажем, Time1) есть 2 или 3 отдельных запроса на передачу (скажем, транзакции 1, транзакции 2, транзакции 3) одинаковой суммы.Сейчас выделенная сумма составляет 500 долларов.Если все переводы начнутся в одно и то же время, все ли тесты будут доступны на сумму ($ 500)?что будет верно, и следующее утверждение переведет средства на другой счет.

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

Спасибо

Ответы [ 2 ]

1 голос
/ 20 июля 2011

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

SET XACT_ABORT, NOCOUNT ON;
BEGIN TRY

    BEGIN TRANSACTION

    SELECT @balance = Balance
    FROM SomeTable WITH (ROWLOCK, HOLDLOCK, UPDLOCK)
    WHERE Account = 'ABC'

    --some checks

    UPDATE ...

    COMMIT TRANSACTION
END TRY
BEGIN CATCH
  ...
END CATCH

Альтернатива состоит в том, чтобы сделать это за один раз, что более целесообразно, если задействована одна таблица. CROSS JOIN - это тест на

SET XACT_ABORT, NOCOUNT ON;
BEGIN TRY

    --BEGIN TRANSACTION

    UPDATE SomeTable WITH (ROWLOCK, HOLDLOCK, UPDLOCK)
    SET Balance = Balance - @request
    WHERE
       ST.Account = 'ABC' AND Balance > @request;
    IF @@ROWCOUNT <> 1
       RAISERROR ('Not enough in account', 16, 1);

    --COMMIT TRANSACTION
END TRY
BEGIN CATCH
  ...
END CATCH
0 голосов
/ 20 июля 2011

Чтобы избежать снятия суммы, превышающей цену, вы можете сделать это:

update <table> 
set amount = amount - @price
where amount >= @price
and account = @account

if @@rowcount = 1 print 'transaction went well' else print 'Insufficient funds'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...