程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 在Linq to Sql中管理並發更新時的沖突(2) 引發更新沖突

在Linq to Sql中管理並發更新時的沖突(2) 引發更新沖突

編輯:關於.NET

在上一講中,我們提到了一些諸如“樂觀並發控制”、“悲 觀並發控制”的概念,以及察看Linq to Sql自動生成sql語句的方法。從 這篇文章起我們將繼續來查看Linq to Sql在管理並發更新時是如何發現沖突問 題的。

要使用Linq to Sql,我們自然需要一個數據庫環境。為了說明問 題,我們這裡使用一個非常簡單的數據表。

我們這裡創建了一個Video表,只有3個字段,沒有約束,沒有外鍵 ——我們只要能夠說明問題就可以了,不是嗎?

VideoID:主 鍵,int,自增長

Introduction:nvarchar(max),not null

SiteID:int,not null

上面的圖片是使用Visual Studio 2008中提供的Object Relational Designer根據

數據表的Schema自動生 成的。您在使用時也可以通過VS 2008提供的命令行工具

“SqlMetal.exe”來自動生成Object Model代碼。這都不是 這次的重點。

目前,Video表中有這麼一條記錄:

VideoID Introduction SiteID 1 Introduction 1 1

現在就開始我們的嘗試吧:

LinqToSqlDemoDataContext dataContext=new LinqToSqlDemoDataContext();
dataContext.Log = Console.Out;
Video video = dataContext.Videos.Single(v => v.VideoID == 1);
video.Introduction = "1235";
dataContext.SubmitChanges();
Console.ReadLine();

首先 ,我們獲取了VideoID為1的那條記錄,並構造成一個Video對象。接著我們修改 了這個Video對象的Introduction屬性,最後調用了DataContext的SubmitChange 方法將修改提交至數據庫。運行以上代碼之後,我們捕獲了輸出:

SELECT [t0].[VideoID], [t0].[Introduction], [t0]. [SiteID]
FROM [dbo].[Video] AS [t0]
WHERE [t0].[VideoID] = @p0
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21004.1
UPDATE [dbo].[Video]
SET [Introduction] = @p3
WHERE ([VideoID] = @p0) AND ([Introduction] = @p1) AND ([SiteID] = @p2)
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
-- @p1: Input NVarChar (Size = 14; Prec = 0; Scale = 0) [Introduction 1]
-- @p2: Input Int (Size = 0; Prec = 0; Scale = 0) [2]
-- @p3: Input NVarChar (Size = 16; Prec = 0; Scale = 0) [New Introduction]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21004.1

獲取VideoID為1的記錄的 Sql語句不必多說,關鍵在於那條用於更新的語句。根據它的WHERE Condition以 及傳入的參數,我們不難發現它在更新時作了什麼樣的判斷:除了傳入了主鍵 ——這是為了標識更新的那條記錄——它還將記錄原有的 值傳入了Sql語句中。也就是說,只有當“更新”時,那條記錄的狀 態和“獲取”時完全相同,更新才會成功。

這就是“樂 觀並發控制”——直到更新時才判斷是否出現了並發問題。

嚴格說來,這只是“樂觀並發控制”的一部分, “樂觀並發控制”
 還包括在並發問題出現之後“處理 問題”的過程。

這種“樂觀並發控制”方式(以後 還會提到其他的“樂觀並法控制”方式)的一個特點是,它並不關心 這條記錄是否被“修改過”,而只是比較當前以及之前的狀態是否相 同(可能記錄被修改過,但是數值保持不變,不是嗎?)。那麼我們來嘗試著產 生以下並發問題吧:try
{
LinqToSqlDemoDataContext dataContext=new LinqToSqlDemoDataContext();
  Video video = dataContext.Videos.Single(v => v.VideoID == 1);
   //

在下一行代碼上設斷點,並在運行時改變數據庫內紀錄的值 。  video.Introduction = "12356";
   dataContext.SubmitChanges();
}
catch (ChangeConflictException e)
{
  Console.WriteLine (e.Message);
}
Console.ReadLine();

現在,我們需 要在改變video對象屬性的那行代碼上設置斷點,並且在運行進入該斷點時改變 該紀錄任一字段的值(例如:UPDATE Video SET SiteID = 10 WHERE VideoID = 1)。當我們繼續運行程序時,就會發現SubmitChange方法拋出了異常,而控制 台輸出了以下字樣:

Row not found or changed.

我們 很容易想到,這是由於WHERE條件沒有滿足,導致了更新時ExecuteNonQuery方法 返回了0,於是Linq to Sql意識到該記錄被修改了(或者被刪除了,從另一個角 度上來看,這也是一種改變)。我們使用以下的方法再進行一次實驗:

LinqToSqlDemoDataContext dataContext =new LinqToSqlDemoDataContext();
dataContext.Log = Console.Out;
Video video = new Video();
video.VideoID = 1;
dataContext.Videos.Attach(video, false);
video.Introduction = "123";
dataContext.SubmitChanges();

猜猜現在的 輸出是什麼?想清楚了嗎?那麼我們來揭曉答案:

UPDATE [dbo].[Video]
SET [Introduction] = @p0
WHERE 0 = 1
-- @p0: Input NVarChar (Size = 3; Prec = 0; Scale = 0) [123]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21004.1

看看WHERE條件:“0 == 1”,這是什麼意思 ?Attach方法又是做什麼的呢?關於這些問題我們以後再進行討論。不過可以得 知的是,這個絕對不成立的WHERE條件不會更新任何記錄,於是Linq to Sql又拋 出了ChangeConflictException。

不過,您是否覺得“樂觀並發控 制”的這種方式非常古怪(累贅?)呢?下一篇文章我們再來更進一步的 討論。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved