SQLServer陷阱 四 隱性鎖

2021-04-18 06:52:02 字數 2084 閱讀 2173

預設情況下select會使用共享鎖, 在資料讀取完後會立即釋放; insert, update, delete會對更改的資料使用排它鎖並且一直保持到事務結束. 共享鎖可以與共享鎖,更新鎖共存. 排它鎖與任何鎖都不能共存.

例1: 新建一張表 create table table1 (id int), 加入一條記錄 insert into table1 values(1) 在查詢分析器中開兩個連線 連線1:

begin

tran

select

*from

table1

連線2:

update

table1

setid =1

先執行連線1, 再執行連線2, 都是立即完成. 然後連線1改為:

while

@@trancount

>

0rollback

tran

--如果有未提交的事務就回滾

begin

tran

update

table1

setid =1

連線2不變 先執行連線1, 再執行連線2, 會發現連線2被阻塞. 這時在連線1中單獨執行commit tran, 連線2會立即結束. 注:在測試過程中可以用select @@spid檢視當前連線的spid, 用sp_lock檢視鎖資訊. 如果要改變隱性鎖, 可以使用with關鍵字.

例2:

連線1:

while

@@trancount

>

0rollback

tran

begin

tran

select

*from

table1

with

(holdlock

)

連線2:

update

table1

setid =1

先執行連線1, 再執行連線2, 連線2會被阻塞. 因為holdlock改變了共享鎖的生存期, 讓共享鎖保持到事務結束, 而共享鎖與排它鎖是不能共存的.

連線1改為:

while

@@trancount

>

0rollback

tran

begin

tran

select

*from

table1

with

(tablockx)

先執行連線1, 再執行連線2, 連線2仍會被阻塞. 這裡指定select使用表級排它鎖, 該鎖會保持到事務結束, 所以這裡不用加holdlock.

例3:

連線1:

while

@@trancount

>

0rollback

tran

insert

into

table1

values(2

)begin

tran

update

table1

setid =3

where

id =

2

連線2:

select

*from

table1

先執行連線1, 再執行連線2, 連線2會被阻塞. 連線2:

select top 1 * from table1

再執行連線2, 連線2會立即結束. 為了使鎖定的成本減至最少,sql server 自動將資源鎖定在適合任務的級別. 這裡會使用行級鎖. update的過程應該先是查詢id=2的記錄, 查詢時使用共享鎖, 不滿足id=2的記錄共享鎖立即釋放, 滿足id=2的記錄把共享鎖公升級為排它鎖並保持到事務結束. 所以第一次執行連線2會因為無法獲取id=2的記錄的共享鎖而被阻塞, 而第二次執行不會被阻塞.

golang 併發鎖的陷阱

package main import sync strconv fmt type node struct var cache node func main cache 1 node wg sync.waitgroup for i 0 i 10000 i i wg.wait fmt.println ...

SQL server鎖的機制

sql server 的所有活動都會產生鎖。鎖定的單元越小,就越能越能提高併發處理能力,但是管理鎖的開銷越大。如何找到平衡點,使併發性和效能都可接受是 sql server 的難點。sql server 有如下幾種瑣 1 共享鎖用於唯讀操作 select 鎖定共享的資源。共享鎖不會阻止其他使用者讀,...

SQL Server 控制鎖公升級

背景知識 鎖公升級的路線圖 行 頁 區 extent 區 表分割槽 表 alter table 控制鎖的公升級行為 1 table sql server 2008中的預設行為,設為這個值時,在表級別啟用了鎖公升級,不管表是否分割槽。2 auto 如果以分割槽就在分割槽級別啟用鎖公升級,如果沒有分割槽...