Bu durumu aşağıdaki test kutusunda yeniden oluşturdum.
Ben bir tablo vardır:
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
Bu tablodan bir kayıt seçmek için ilk çalışıyorum ve kayıt şimdiki zaman artı bazı aralığına ayarlamak geçerlilik süresini varsa. Bu şu kod kullanılarak gerçekleştirilir: İki iş parçacığı gelen test yöntemini yürütmek çalışırsanız Sonra
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();
}
}
}
ve onlar çıktı şu olsun aynı kaydı güncellemeyi deneyin: Ben anlayamıyorum
[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.
Seri hale getirilebilir yalıtım düzeyi kullanılarak gerçekleşebilir. İlk seçimde satır/tabloyu kilitlemeli ve başka bir kilitlenmeyi seçmemize izin vermemeliyim. Örnek komut nesneleri kullanılarak yazılmıştır, ancak sadece test amaçlıdır. Aslında linq kullanıyorum ama basitleştirilmiş örnek göstermek istedim. Sql Server Profiler kilitlenme kilit kilit olduğunu gösterir. Soruyu birkaç dakika içinde güncelleyeceğim ve sql server profilerden grafik yayınlayacağım. Herhangi bir yardım takdir edilecektir. Bu sorunun çözümünün kodda kritik bölüm oluşturduğunu anlıyorum, ancak Seri hale getirilebilir Yalıtım Seviyesinin neden hile yapmadığını anlamaya çalışıyorum. peşin deadlock http://img7.imageshack.us/img7/9970/deadlock.gif
Teşekkür: Burada
Ve
kilitlenme grafiktir.
+1! –