天天看點

有關資料庫鎖的一系列問題

怎樣用SQL語句對資料庫表進行加鎖和解鎖? .

分類: 資料庫 2010-03-20 09:29 1220人閱讀 評論(0) 收藏 舉報

鎖是資料庫中的一個非常重要的概念,它主要用于多使用者環境下保證資料庫完整性和一緻性。 我們知道,多個使用者能夠同時操縱同一個資料庫中的資料,會發生資料不一緻現象。即如果沒有鎖定且多個使用者同時通路一個資料庫,則當他們的事務同時使用相同的資料時可能會發生問題。這些問題包括:丢失更新、髒讀、不可重複讀和幻覺讀:

1.當兩個或多個事務選擇同一行,然後基于最初標明的值更新該行時,會發生丢失更新問題。每個事務都不知道其它事務的存在。最後的更新将重寫由其它事務所做的更新,這将導緻資料丢失。例如,兩個編輯人員制作了同一文檔的電子複本。每個編輯人員獨立地更改其複本,然後儲存更改後的複本,這樣就覆寫了原始文檔。最後儲存其更改複本的編輯人員覆寫了第一個編輯人員所做的更改。如果在第一個編輯人員完成之後第二個編輯人員才能進行更改,則可以避免該問題。

2. 髒讀就是指當一個事務正在通路資料,并且對資料進行了修改,而這種修改還沒有送出到資料庫中,這時,另外一個事務也通路這個資料,然後使用了這個資料。因為這個資料是還沒有送出的資料,那麼另外一個事務讀到的這個資料是髒資料,依據髒資料所做的操作可能是不正确的。例如,一個編輯人員正在更改電子文檔。在更改過程中,另一個編輯人員複制了該文檔(該複本包含到目前為止所做的全部更改)并将其分發給預期的使用者。此後,第一個編輯人員認為目前所做的更改是錯誤的,于是删除了所做的編輯并儲存了文檔。分發給使用者的文檔包含不再存在的編輯内容,并且這些編輯内容應認為從未存在過。如果在第一個編輯人員确定最終更改前任何人都不能讀取更改的文檔,則可以避免該問題。

3.不可重複讀是指在一個事務内,多次讀同一資料。在這個事務還沒有結束時,另外一個事務也通路該同一資料。那麼,在第一個事務中的兩次讀資料之間,由于第二個事務的修改,那麼第一個事務兩次讀到的的資料可能是不一樣的。這樣就發生了在一個事務内兩次讀到的資料是不一樣的,是以稱為是不可重複讀。例如,一個編輯人員兩次讀取同一文檔,但在兩次讀取之間,作者重寫了該文檔。當編輯人員第二次讀取文檔時,文檔已更改。原始讀取不可重複。如果隻有在作者全部完成編寫後編輯人員才可以讀取文檔,則可以避免該問題。

4.幻覺讀是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的資料進行了修改,這種修改涉及到表中的全部資料行。同時,第二個事務也修改這個表中的資料,這種修改是向表中插入一行新資料。那麼,以後就會發生操作第一個事務的使用者發現表中還有沒有修改的資料行,就好象發生了幻覺一樣。例如,一個編輯人員更改作者送出的文檔,但當生産部門将其更改内容合并到該文檔的主複本時,發現作者已将未編輯的新材料添加到該文檔中。如果在編輯人員和生産部門完成對原始文檔的處理之前,任何人都不能将新材料添加到文檔中,則可以避免該問題。

是以,處理多使用者并發通路的方法是加鎖。鎖是防止其他事務通路指定的資源控制、實作并發控制的一種主要手段。當一個使用者鎖住資料庫中的某個對象時,其他使用者就不能再通路該對象。加鎖對并發通路的影響展現在鎖的粒度上。為了控制鎖定的資源,應該首先了解系統的空間管理。在SQL Server 2000系統中,最小的空間管理機關是頁,一個頁有8K。所有的資料、日志、索引都存放在頁上。另外,使用頁有一個限制,這就是表中的一行資料必須在同一個頁上,不能跨頁。頁上面的空間管理機關是盤區,一個盤區是8個連續的頁。表和索引的最小占用機關是盤區。資料庫是由一個或者多個表或者索引組成,即是由多個

SQL語句:

LOCK TABLES tablename WRITE;

LOCK TABLES tablename READ;

INSERT INTO assignment VALUES (1,7513,'0000-00-00',5),(1,7513,'2003-01-20',8.5);

UNLOCK TABLES;

對于多個使用者同時送出表單,并且同時向資料庫中得到表單ID,我是這樣解決的:

mysql_query("lock tables po read");

mysql_query("lock tables po write");

mysql_query("update po set id=id +1"));// increase po id

$sql = "SELECT id FROM po";

$result = mysql_query($sql);

if ($row = mysql_fetch_assoc($result)) {

echo $row["id"]; // this order will use this id

}

mysql_free_result($result);

mysql_query("unlock tables");

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

幫忙看看如何在這段代碼前後給資料庫寫加鎖和解鎖語句

'(在這裡給資料庫加鎖,如何寫加鎖語句?)

...............

i = str(從記錄集rst0中得到最大入庫單号)

'若不加鎖,在這容易造成并發沖突。因為在申請到最大入庫單号之後還沒有來得及建立實際記錄,其它用戶端可能也申請到了同樣的入庫單号

..............

rst.open "select * from 入庫 where 入庫單号= " + i + " and 商品ID=0 ", cn, adOpenStatic, adLockOptimistic

If rst.RecordCount = 0 Then 下一個入庫單号 = i + 1

...............

'(在這裡給資料庫解鎖,如何寫解鎖語句?)

解答1:先将需要加鎖執行的語句聲明成一個事務(如2樓),然後加鎖,SQL Server中鎖的類型很多,看你需要加哪種類型的鎖:

HOLDLOCK 将共享鎖保留到事務完成,而不是在相應的表、行或資料頁不再需要時就立即釋放鎖。HOLDLOCK 等同于 SERIALIZABLE。

NOLOCK 不要發出共享鎖,并且不要提供排它鎖。當此選項生效時,可能會讀取未送出的事務或一組在讀取中間復原的頁面。有可能發生髒讀。僅應用于 SELECT 語句。

PAGLOCK 在通常使用單個表鎖的地方采用頁鎖。

READCOMMITTED 用與運作在送出讀隔離級别的事務相同的鎖語義執行掃描。預設情況下,SQL Server 2000 在此隔離級别上操作。

READPAST 跳過鎖定行。此選項導緻事務跳過由其它事務鎖定的行(這些行平常會顯示在結果集内),而不是阻塞該事務,使其等待其它事務釋放在這些行上的鎖。 READPAST 鎖提示僅适用于運作在送出讀隔離級别的事務,并且隻在行級鎖之後讀取。僅适用于 SELECT 語句。

READUNCOMMITTED 等同于 NOLOCK。

REPEATABLEREAD 用與運作在可重複讀隔離級别的事務相同的鎖語義執行掃描。

ROWLOCK 使用行級鎖,而不使用粒度更粗的頁級鎖和表級鎖。

SERIALIZABLE 用與運作在可串行讀隔離級别的事務相同的鎖語義執行掃描。等同于 HOLDLOCK。

TABLOCK 使用表鎖代替粒度更細的行級鎖或頁級鎖。在語句結束前,SQL Server 一直持有該鎖。但是,如果同時指定 HOLDLOCK,那麼在事務結束之前,鎖将被一直持有。

TABLOCKX 使用表的排它鎖。該鎖可以防止其它事務讀取或更新表,并在語句或事務結束前一直持有。

UPDLOCK 讀取表時使用更新鎖,而不使用共享鎖,并将鎖一直保留到語句或事務的結束。UPDLOCK 的優點是允許您讀取資料(不阻塞其它事務)并在以後更新資料,同時確定自從上次讀取資料後資料沒有被更改。

XLOCK 使用排它鎖并一直保持到由語句處理的所有資料上的事務結束時。可以使用 PAGLOCK 或 TABLOCK 指定該鎖,這種情況下排它鎖适用于适當級别的粒度。

解答2”要使一表在整個處理過程中不會被并發修改

可用事務

begin tran

select * from 表名 with HOLDLOCK

--處理語句

........

............

commit tran

加了 with holdlock後,在事務送出之前,别人動不了你的表

。。。。。。。。。。。。。。。。。。。。。。。。。。。。