Pergunta

O problema que tenho é esta:

Eu tenho uma tabela (apenas um exemplo) com os seguintes campos:

ID int
Value int

Eu tenho um método chamado IncreaseByFive () que faz o seguinte:

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

O que eu quero evitar é a seguinte situação:

  1. Um usuário chama o método e obtém o valor (atualmente 5)
  2. O usuário B chama o método e obtém o valor (atualmente 5)
  3. Um usuário aumenta o valor de 5 (agora 10)
  4. O usuário B aumenta o valor de 5 (agora 10)
  5. Um usuário salva o valor (10)
  6. O usuário B salva o valor (10)

Agora, o registro tem um valor de 10, quando deveria ter sido 15.

O que eu quero força é o seguinte:

  1. Um usuário chama o método e obtém o valor (atualmente 5)
  2. O usuário B chama o método, mas tem que esperar porque um já chamou. (Dibs!)
  3. Um usuário aumenta o valor (agora 10)
  4. O usuário B ainda está à espera
  5. Um usuário salva o valor (registro tem o valor de 10)
  6. O usuário B pode agora ler o valor (10)
  7. O usuário B aumenta o valor (15)
  8. O usuário B salva o valor

Agora, o registro tem um valor de 15, que é o resultado que eu estou procurando.

Eu já resolveu este problema no passado usando uma classe estática e colocar um bloqueio em um objeto estático criado dentro do construtor dessa classe, canalizando assim todo o trabalho através de um método estático, o que obriga as outras chamadas de esperar na fila . Receio, porém, que isso não é escalável.

Eu também acho que o mais alto nível de isolamento (serializável) para uma transação não irá fazer o truque, quer porque vai permitir a leitura no passo 2 do exemplo indesejado acima.

Eu suponho que outra solução seria criar minha própria mesa de bloqueio e gravar as fechaduras lá, mas que parece que não deve ser necessário.

Estou desenvolvendo esse projeto com C # (3.5) e SQL Server 2008.

O que a mente da colmeia acha?

Foi útil?

Solução

Talvez eu seja mais underthinking isso, mas você não iria só embrulhar todo o bloco lógica ..

  • valor lido
  • valor escrita

em uma transação do banco de dados do rel="nofollow noreferrer"> nível adequado

SET TRANSACTION ISOLATION LEVEL
    { READ UNCOMMITTED
    | READ COMMITTED
    | REPEATABLE READ
    | SNAPSHOT
    | SERIALIZABLE
    }
[ ; ]
scroll top