通常我們?cè)谶M(jìn)行數(shù)據(jù)庫(kù)的新增、修改、刪除、查詢的時(shí)候如果我們面對(duì)的不是多個(gè)用戶也及時(shí)單機(jī)處理的時(shí)候, 一般我們基本上不需要考慮數(shù)據(jù)庫(kù)的表鎖定以及死鎖之類(lèi)情況,但是如果我們面對(duì)的是多用戶的并行處理的 網(wǎng)絡(luò)環(huán)境的時(shí)候我們對(duì)表鎖定的問(wèn)題就需要較為仔細(xì)的分析和考慮,否則他給我們帶來(lái)的麻煩就不言而喻了, 下面就把我的在這件事情上遇到的問(wèn)題以及解決辦法同大家一起分享。 也是在我的開(kāi)發(fā)過(guò)程當(dāng)中有這樣的事情: 兩個(gè)用戶同時(shí)保存新增的數(shù)據(jù),我們的程序開(kāi)始是這樣處理 cn.begintrans cn.execute "insert into tablea ....." set rs = cn.execute("select count(*) from tablea where ...") if rs.recordcount > 0 then '表a 的字段a不能從復(fù) cn.rollbacktrans else cn.committrans end if
當(dāng)sql server 在執(zhí)行insert 命令時(shí)如果我們不添加任何參數(shù)時(shí) 數(shù)據(jù)庫(kù)默認(rèn)申請(qǐng)一個(gè) ix 鎖 給表a 這時(shí)候我們來(lái)分析上面的程序,當(dāng)?shù)谝粋€(gè)用戶執(zhí)行 cn.execute "insert into tablea ....." connection 向數(shù)據(jù)庫(kù)申請(qǐng)了一個(gè) ix 鎖 給表a ,與此同時(shí)當(dāng)?shù)诙€(gè)用戶執(zhí)行 cn.execute "insert into tablea ....." connection 也向數(shù)據(jù)庫(kù)也成功地申請(qǐng)了一個(gè) ix 鎖 給表a ,但是當(dāng)執(zhí)行 set rs = cn.execute("select count(*) from tablea where ...") 這一句的時(shí)候就會(huì)有問(wèn)題產(chǎn)生,我們假設(shè)第一個(gè)用戶先一步執(zhí)行 ,由于select命令需要向數(shù)據(jù)庫(kù)申請(qǐng)一個(gè) s 鎖給表a,但是由于這時(shí)候表a已經(jīng)存在一個(gè)ix鎖并且屬于另外一個(gè)連接因此他只好在此等候。緊接著第二個(gè) 用戶也執(zhí)行 set rs = cn.execute("select count(*) from tablea where ...") 他也會(huì)向數(shù)據(jù)庫(kù)申請(qǐng)一個(gè)s 鎖給表a ,這時(shí)候數(shù)據(jù)就會(huì)自動(dòng)結(jié)束較晚申請(qǐng)ix鎖的連接同時(shí)回滾這個(gè)事務(wù) 這樣子對(duì)于我們的應(yīng)用來(lái)說(shuō)就是一個(gè)很大的失敗。
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不能從復(fù) cn.rollbacktrans else cn.committrans end if cn.execute "set transaction isolation level read committed "
解決的辦法二,設(shè)置insert 命令 參數(shù) 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不能從復(fù) cn.rollbacktrans else cn.committrans end if
解決的辦法三,增加一個(gè)沒(méi)有用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不能從復(fù) cn.rollbacktrans else cn.committrans end if