Deadlock em SELECT / UPDATE

Estou tendo um problema com deadlock no SELECT / UPDATE no SQL Server 2008. Li as respostas deste tópico:eadlocks do @SQL Server entre selecionar / atualizar ou várias seleções mas ainda não entendo por que estou com um impasse.

Recriei a situação no seguinte caso de test

Tenho uma mesa:

CREATE TABLE [dbo].[SessionTest](
    [SessionId] UNIQUEIDENTIFIER ROWGUIDCOL NOT NULL,
    [ExpirationTime] DATETIME NOT NULL,
    CONSTRAINT [PK_SessionTest] PRIMARY KEY CLUSTERED (
        [SessionId] ASC
    ) WITH (
        PAD_INDEX  = OFF, 
        STATISTICS_NORECOMPUTE  = OFF, 
        IGNORE_DUP_KEY = OFF, 
        ALLOW_ROW_LOCKS  = ON, 
        ALLOW_PAGE_LOCKS  = ON
    ) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[SessionTest] 
    ADD CONSTRAINT [DF_SessionTest_SessionId] 
    DEFAULT (NEWID()) FOR [SessionId]
GO

Estou tentando primeiro selecionar um registro nesta tabela e, se o registro existir, defina o tempo de expiração para o tempo atual mais algum intervalo. Isso é realizado usando o seguinte código:

protected Guid? GetSessionById(Guid sessionId, SqlConnection connection, SqlTransaction transaction)
{
    Logger.LogInfo("Getting session by id");
    using (SqlCommand command = new SqlCommand())
    {
        command.CommandText = "SELECT * FROM SessionTest WHERE SessionId = @SessionId";
        command.Connection = connection;
        command.Transaction = transaction;
        command.Parameters.Add(new SqlParameter("@SessionId", sessionId));

        using (SqlDataReader reader = command.ExecuteReader())
        {
            if (reader.Read())
            {
                Logger.LogInfo("Got it");
                return (Guid)reader["SessionId"];
            }
            else
            {
                return null;
            }
        }
    }
}

protected int UpdateSession(Guid sessionId, SqlConnection connection, SqlTransaction transaction)
{
    Logger.LogInfo("Updating session");
    using (SqlCommand command = new SqlCommand())
    {
        command.CommandText = "UPDATE SessionTest SET ExpirationTime = @ExpirationTime WHERE SessionId = @SessionId";
        command.Connection = connection;
        command.Transaction = transaction;
        command.Parameters.Add(new SqlParameter("@ExpirationTime", DateTime.Now.AddMinutes(20)));
        command.Parameters.Add(new SqlParameter("@SessionId", sessionId));
        int result = command.ExecuteNonQuery();
        Logger.LogInfo("Updated");
        return result;
    }
}

public void UpdateSessionTest(Guid sessionId)
{
    using (SqlConnection connection = GetConnection())
    {
        using (SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.Serializable))
        {
            if (GetSessionById(sessionId, connection, transaction) != null)
            {
                Thread.Sleep(1000);
                UpdateSession(sessionId, connection, transaction);
            }
            transaction.Commit();
        }
    }
}

Então, se eu tentar executar o método de teste a partir de dois threads e eles tentarem atualizar o mesmo registro, recebo a seguinte saída:

[4] : Creating/updating session
[3] : Creating/updating session
[3] : Getting session by id
[3] : Got it
[4] : Getting session by id
[4] : Got it
[3] : Updating session
[4] : Updating session
[3] : Updated
[4] : Exception: Transaction (Process ID 59) was deadlocked 
on lock resources with another process and has been 
chosen as the deadlock victim. Rerun the transaction.

Não consigo entender como isso pode acontecer usando o nível de isolamento serializável. Eu acho que o primeiro select deve bloquear a linha / tabela e não permitirá que outro selecione para obter bloqueios. O exemplo é escrito usando objetos de comando, mas é apenas para fins de teste. Originalmente, estou usando o linq, mas queria mostrar um exemplo simplificado. O Sql Server Profiler mostra que o deadlock é o bloqueio de chave. Atualizarei a questão em alguns minutos e publicarei o gráfico do sql server profiler. Qualquer ajuda seria apreciada. Entendo que a solução para esse problema pode estar criando uma seção crítica no código, mas estou tentando entender por que o Nível de isolamento serializável não funcion

E aqui está o gráfico de impasse:deadlock http://img7.imageshack.us/img7/9970/deadlock.gi

Desde já, obrigado

questionAnswers(2)

yourAnswerToTheQuestion