在資料庫維護的過程中,資料庫管理員可能有這方面的需求。管理員要求某表中的部分資料暫時只有他自己或者某個特定的使用者可以更改,而其他使用者則只能
夠查詢。如為了核對資料的需要,要暫時拒絕使用者更改某些資料。這就好像在Excel表格中,對某些行進行保護。當某個使用者訪問這張表格時,其他使用者只能夠
查看錶格中的內容,對於受保護的資料,其他使用者不能夠更改、刪除等等。
在Oracle資料庫中可以實現這個需求嗎?在資料庫中,有多種方式可以實現這種方式。如將這個表所在的資料表空間設定為唯讀,或者通過更改許可權來
完成,設定其他使用者對這個表只有唯讀許可權。但是,這些方法都有點小題大做。如將某個資料表空間設定為唯讀,那麼任何使用者都不能夠對其中的資料變更;而且
如果資料表空間中有很多表的話,受影響的表格會很多。如通過許可權來控制雖然可以減少範圍,但是資料庫管理員可能只需要保護表中某些資料。即除了受保護的資料之
外,其他的使用者仍然可以正常訪問,如可以刪除、更新等等。所以,以上這兩種方法雖然可以最終實現這個需求,但是由於其牽涉面太廣,會在很大程度上影響其他
使用者的正常使用。為此這兩個方法並不是筆者推薦的方法。筆者推薦的是通過行級鎖來完成。下面筆者就將對這個方法進行詳細的闡述,特別會強調使用過程中的注
意點。
如現在資料庫中有system與victor兩個使用者,有一個dtm_pro表。現在資料庫管理員希望對這張表中的部分資料進行保護。如希望
RECID1小於450的記錄暫時其他使用者不能夠更改。其他使用者之能夠查詢這些記錄,而不能夠刪除或者更改。為了減少使用者使用資料庫的不利影響,資料庫管
理員要求對於RECID1大於等於450以上的記錄,使用者可以正常的刪除或者更改等等。如所示,這就是具體的實現過程。
從中可以看出,筆者在查詢語句中,加入for update of THREAD# wait
5子句。通過這個子句可以實現行級鎖,從而保護結果集中的資料。
一、行級鎖的特徵。
在Oracle資料庫中,主要是通過鎖來管理共用資源的。簡單的說,鎖就是控制當有多個使用者同時訪問相同的共用資源時,彼此對資料的一種額外的
許可權控制。在Oracle資料庫中,鎖可以分為行級鎖與表級鎖。筆者這裡要談的是行級鎖。行級鎖顧名思義,就是對錶中的部分行加鎖的一種控制機制。在理解
這個行級鎖的時候,筆者認為需要注意如下幾個方面。
首先需要注意之所以稱為行級鎖,就是因為其受影響的範圍只是部分的行,而不是表中的全部行。如上例所示,其所影響的行就是where條件所限制
的結果級。即只是鎖住where條件查詢出來的結果集。而對於其他的行不受影響。其他使用者可以刪除、更改沒被加鎖的行。通過這種方式,就可以將鎖對其他用
戶的資料庫操作的不利影響降低到最低。從而實現效率與安全的並重。
第二需要注意的是,行級鎖是一個排他的所。假設現在上面這兩個使用者都有對錶dtm_pro加鎖的權利。在上例中,先由使用者system對錶中
RECID1小於450的記錄加了鎖。此時其他使用者如victor即使其有這個權利,也無法對這張表中的這些記錄進行加鎖。因為行級鎖是排他的。如果硬要
加鎖的話,則會發生死結的現象。此時除非資料庫管理員人為的利用語句進行解鎖,否則的話這個死結會長時間存在。
二、行級鎖的分類。
在Oracle資料庫中行級鎖主要分為兩類,一類是自動行級鎖。這個自動行級鎖是指不需要再語句中採用for update
語句資料庫就會自動加鎖的方法。這個自動行級鎖主要是某些特定的語句所觸發的。如現在使用update更新表中的部分資料,在更新完成後事務沒有遞交之
前,資料庫會自動對受影響的記錄進行加鎖,從而實現資料的一致性。這個行級鎖雖然是資料庫自動增加的,但是往往解鎖的時候需要使用者手工解鎖。即在語句中加
入commit(將更新資料寫入到資料庫中)或者rollback(取消資料的更改)來手工解鎖。為此在書寫刪除或者更新等語句時,一定不要忘記在最後加
上一個解鎖的語句。否則的話,當其他人也對這些記錄進行更新或者刪除操作時,會造成死結的現象。
第二類就是手工加鎖。自動加鎖只是針對一些更新或者刪除動作陳述式有效,而對於普通的查詢語句是無效的。既使用者平時在利用select語句查詢資料
時,是不會對相關的記錄加鎖的。而現在如果使用者需要對某些查詢的資料強制加鎖的話,那麼就需要利用for update
語句手工的為相關的記錄進行加鎖。當手工加鎖之後,與資料庫系統自動加鎖效果是一樣的。加鎖後,加鎖的使用者可以對相關的記錄進行刪除、更新、查詢等操作。
而其他使用者的話,對這些記錄只有查詢的許可權。同理,當相關的工作完成後,使用者要即使的把這個鎖解鎖掉。系統不會自動對此進行解鎖。
從這裡也可以看出鎖不一定是資料庫系統專用的對象。當使用者或者資料庫管理員覺得有必要的時候,也可以對某些記錄進行手工的加鎖,以防止其他使用者
對這些進行變更。當使用者覺得某些資料有問題,絕對可能存在弄虛作假的情況,此時對這些受懷疑的資料進行鎖定,防止使用者對這些資料進行篡改。此時利用這
個行級鎖就非常的有用。因為此時只對特定的記錄進行加鎖,而不影響表中其他資料的使用。不過資料庫管理員需要注意的是,鎖是保護資料安全的一種機制,其跟
效率往往是相互衝突的。為此在採用鎖的時候,需要注意對於資料庫運行效率與使用者工作效率可能帶來的負面影響。
三、行級鎖使用過程中的注意事項。
雖然行級鎖可以實現對部分資料的保護,但是其畢竟與資料庫的工作效率是背道而馳的。為此資料庫管理員在管理行級鎖的時候,需要注意其對資料庫工
作效率所造成的負面影響。具體的來說,筆者認為以下三點注意事項要引起大家的重視。
一是行級鎖是獨佔鎖定。對於這個獨佔鎖定,使用者需要瞭解其兩層含意。第一是對於已經鎖定的記錄,其他使用者不能夠再在這些記錄上加鎖。如上例所示,用
戶system已經對兩條記錄加鎖了,此時使用者victor不但不能夠修改或者刪除資料,也不能夠對這些記錄重新加鎖。這就是獨佔鎖定的含義。只有一個使用者
可以對特定的記錄進行加鎖。第二是對於已經加鎖以外的資料,其他使用者仍然可以加鎖。如上例中,使用者system雖然已經對其中兩條記錄加鎖了,但是使用者
victor仍然可以利用行級鎖對其餘的記錄進行加鎖。所以說,這個獨佔鎖定只是對於特定的記錄來說的,而不是對整個表格來說的。不同的使用者可以在各自的記
錄上加行級鎖,此時記錄不能夠重複。
二是需要注意死結的問題。如所示,使用者system已經對某些記錄加鎖了,此時如果使用者victor對這些記錄也進行加鎖操作的話,那麼就
會造成死結,因為行級鎖是獨佔鎖定。當發生死結現象時,使用者victor的會話會一直等待自願的解鎖,如果使用者system一百年沒有解鎖的話,那麼
victor會一直等待下去。顯然這並不是資料庫管理員所希望看到的。為此在手工添加行級鎖得時候,最好能夠添加wati子句。這個子句是用來控制當發生
死結時,會話等待解鎖的時間。如果超過這個時間,對方還沒有對資源解鎖的話,則系統會自動放棄操作,並向使用者返回錯誤資訊:資源已經被佔用,執行操作時出
現Wait錯誤。可見,假如這個子句的話,可以有效避免死結對使用者會話的不利影響。這個等待的時間使用者可以根據自己的需要來設定。不過一般情況下不要把這
個時間設定的太長。
三是在實現行級鎖的時候,最好利用where條件陳述式來限制所影響的記錄。如上面例子中,筆者加入了where條件陳述式,此時最後受行級鎖影響
的記錄只有兩條。如果沒有加入這個where語句的時候,則整個表的記錄都會被加鎖了。此時就會對其他使用者的操作產生很大的影響,不能夠對整個表的資料進
行更新、刪除等操作。為此在使用行級鎖的時候,最好能夠將範圍限制在最小,即只對必要的記錄採用行級鎖。從而在保護資料一致性的同時,將其對使用者的不利影
響降低到最低,提高資料庫的運行效率,實現效率與安全的均衡。