通常我們在進行數據庫的新增、修改、刪除、查詢的時候如果我們面對的不是多個用戶也及時單機處理的時候,一般我們基本上不需要考慮數據庫的表鎖定以及死鎖之類情況,但是如果我們面對的是多用戶的並行處理的網絡環境的時候我們對表鎖定的問題就需要較為仔細的分析和考慮,否則他給我們帶來的麻煩就不言而喻了,下面就把我的在這件事情上遇到的問題以及解決辦法同大家一起分享。
也是在我的開發過程當中有這樣的事情:
兩個用戶同時保存新增的數據,我們的程序開始是這樣處理
cn.BeginTrans
cn.Execute "insert into tableA ....."
Set rs = cn.Execute("select count(*) from tableA where ...")
If rs.RecordCount > 0 Then
'表A 的字段A不能從復
cn.RollbackTrans
Else
cn.CommitTrans
End If
當SQL Server 在執行INSERT 命令時如果我們不添加任何參數時 數據庫默認申請一個 IX 鎖 給表A這時候我們來分析上面的程序,當第一個用戶執行 cn.Execute "insert into tableA ....." Connection
向數據庫申請了一個 IX 鎖 給表A ,與此同時當第二個用戶執行 cn.Execute "insert into tableA ....." Connection 也向數據庫也成功地申請了一個 IX 鎖 給表A ,但是當執行
Set rs = cn.Execute("select count(*) from tableA where ...")
這一句的時候就會有問題產生,我們假設第一個用戶先一步執行 ,由於SELECT命令需要向數據庫申請一個
S 鎖給表A,但是由於這時候表A已經存在一個IX鎖並且屬於另外一個連接因此他只好在此等候。緊接著第二個
用戶也執行
Set rs = cn.Execute("select count(*) from tableA where ...")
他也會向數據庫申請一個S 鎖給表A ,這時候數據就會自動結束較晚申請IX鎖的連接同時回滾這個事務
這樣子對於我們的應用來說就是一個很大的失敗。
解決的辦法一,設置數據參數讓我們可以讀取沒有提交的數據、
cn.BeginTrans
cn.Execute "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED "
cn.Execute "insert into tableA ....."
Set rs = cn.Execute("select count(*) from tableA where ...")
If rs.RecordCount > 0 Then
'表A 的字段A不能從復
cn.RollbackTrans
Else
cn.CommitTrans
End If
cn.Execute "SET TRANSACTION ISOLATION LEVEL READ COMMITTED "
解決的辦法二,設置INSERT 命令 參數 with (tablock) 、
cn.BeginTrans
cn.Execute "insert into tableA with (tablock) ....."
Set rs = cn.Execute("select count(*) from tableA where ...")
If rs.RecordCount > 0 Then
'表A 的字段A不能從復
cn.RollbackTrans
Else
cn.CommitTrans
End If
解決的辦法三,增加一個沒有用Lock 表、
cn.BeginTrans
cn.Execute "update tmpLockTable set FIEldLock=1"
cn.Execute "insert into tableA with (tablock) ....."
Set rs = cn.Execute("select count(*) from tableA where ...")
If rs.RecordCount > 0 Then
'表A 的字段A不
能從復
cn.RollbackTrans
Else
cn.CommitTrans
End If