怎樣用SQL語句對數據庫表進行加鎖和解鎖?

 

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


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後,在事務提交之前,別人動不了你的表
。。。。。。。。。。。。。。。。。。。。。。。。。。。。

 

發佈了209 篇原創文章 · 獲贊 6 · 訪問量 41萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章