一、 編寫有效事務的指導原則
- 不要在事務處理期間要求用戶輸入或消息響應。
在事務啓動之前,獲得所有需要的用戶輸入。如果在事務處理期間還需要其它的用戶輸入,則回滾當前的事務,並在提供了用戶輸入之後重新啓動該事務。即使用戶立即響應,作爲人,其反應時間也要比計算機慢得多。事務佔用的所有資源都要保持很長的時間,這就有可能造成阻塞問題。如果用戶沒有響應,該事務就會仍保持活動狀態,並鎖定關鍵資源,直到他們響應爲止,但是用戶可能會幾分鐘甚至幾小時都不響應。
- 在瀏覽數據時,儘量不要打開事務。
在所有預備的數據分析完成之前,不應啓動事務。
保持事務儘可能地短。
- 在知道了必須要進行的修改之後,啓動事務,執行修改語句,然後立即提交或回滾。只有在需要時,纔打開事務。不要在發出更新語句後,再次進行復雜計算生成數據,再提交和回滾。
- 靈活地使用更低的事務隔離級別。
可以很容易地編寫出許多使用授權讀事務隔離級別的應用程序。並不是所有的事務都要求可串行事務隔離級別。
- 靈活地使用更低的遊標併發選項,如樂觀併發選項。
在很少有可能併發更新的系統中,處理某個偶然的"別人在您讀取數據後更改了該數據"錯誤的開銷,要比在讀取數據時始終鎖定行的開銷小得多。
- 在事務中儘量使訪問的數據量最小。
這樣可以減少鎖定的行數,從而減少事務之間的爭奪。
二、 避免死鎖:
下列方法有助於最大限度地降低死鎖:
· 按同一順序訪問對象。
· 避免事務中的用戶交互。
· 保持事務簡短並在一個批處理中。
· 使用低隔離級別。
三、 觸發器
不要嘗試在觸發器中定義事務,包括begin tran,commit,rollback。
四、 存儲過程:
存儲過程對@@TRANCOUNT應無淨改變,如果 @@TRANCOUNT 的值在存儲過程完成時與過程執行時不同,則會生成一個 266 信息類錯誤.
當調用存儲過程時,如果 @@TRANCOUNT 爲 1 或更大,並且該過程執行 ROLLBACK TRANSACTION 或ROLLBACK WORK 語句,則會產生 266 號錯誤。這是因爲 ROLLBACK 回滾所有未完成的事務,並將 @@TRANCOUNT 減到 0,該值比調用過程時要小。
存儲過程既可以被前臺執行,也可以在後臺執行,凡涉及更新數據的存儲過程,在定義事務時應嚴格遵守以下約定:
--以下爲標準存儲過程事務定義的模板
Create procedure proc_test
As
begin
declare @is_procedure_transaction char(1) --是否是存儲過程定義的事務
declare @local_error int --保存更新錯誤號
if @@trancount = 0 --判斷事務是否嵌套,如無則存儲過程自己定義事務
begin
select @is_procedure_transaction=’1’ --將存儲過程定義的事務標誌置’1’
begin tran tran_procedure --存儲過程自己定義事務
end
--此處爲INSERT,UPDATE,DELETE等更新操作語句,並假定是存儲過程中最後一個更新語句,如果不是最後的更新語句,僅處理錯誤部分
if @@error <> 0 --判斷數據庫更新時是否有錯誤發生
begin --更新有錯誤
set @local_error = @@error
if @is_procedure_transaction=’1’ --判斷事務是否由存儲過程定義
begin
rollback tran --錯誤發生則回滾存儲過程定義的事務,注意不要帶事務名
end
--close cursorname 如果定義有遊標,請關閉
--deallocate cursorname 如果定義有遊標,請釋放
raiserror('數據更新錯誤,SQL錯誤號='+convert(varchar(6), @local_error),16,1) --返回錯誤信息,並顯示SQL錯誤號
return -1
end --更新有錯誤處理結束
else
begin --更新成功
if @is_procedure_transaction=’1’ --判斷事務是否由存儲過程定義
begin
commit tran --更新成功則提交存儲過程定義的事務,注意不要帶事務名
end
--close cursorname 如果定義有遊標,請關閉
--deallocate cursorname 如果定義有遊標,請釋放
return 0
end --更新成功處理結束
end --結束整個存儲過程
go
五、 隔離級別與鎖模式
l 數據一致性要求與併發性要求是一個矛盾體,數據一致性要求高則併發性就差,否則併發性要求高則數據一致性要求相對要求就低一些。應根據具體情況處理。
l 爲避免髒讀、不可重複讀取或幻像讀取,引入數據事務隔離級別定義:SET TRANSACTION ISOLATION LEVEL { READ COMMITTED| READUNCOMMITTED| EPEATABLE READ| SERIALIZABLE }
,
一次只能設置這些選項中的一個,而且設置的選項將一直對那個連接保持有效,直到顯式更改該選項爲止。這是默認行爲,除非在語句的 FROM 子句中在表級上指定優化選項。SET TRANSACTIONISOLATION
LEVEL 的設置是在執行或運行時設置,而不是在分析時設置。其中READCOMMITTED爲Mssqlserver的默認設置。
USE pubs
GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
GO
BEGIN TRANSACTION
SELECT au_lname FROM authors WITH (NOLOCK)
GO
EXEC sp_lock
GO
檢查加鎖情況發現引用 authors 唯一採用的鎖是架構穩定性 (Sch-S) 鎖。在這種情況下不能保證可串行性