--維護數據庫--
--事務(transaction)和鎖--
--事務(transaction)--
--概述:
事務是指封裝了一組T-SQL語句的單個邏輯單元。單元中的所有語句作為一個整體,在滿足一定條件是全部執行(提交事務),或因不滿足條件而全部執行(回滾事務)。
在同一數據庫中的數據在操作時可能是相互影響的,如果數據再互相影響的操作中發生,可以使用事務解決。
--事務的屬性:事務的定義(聲明)、執行(提交)、撤銷(回滾)操作一旦發生,必須滿足四個屬性,即ACID屬性。
1)原子性:事務作為一個獨立的邏輯單元,被稱為原子單元。它的執行是一次性的,要麼事務中的所有事件都完成,要麼不執行事務中的任何事件。
2)一致性:事務提交或回滾操作成功執行後,所有數據必須保持從一種狀態到另一種狀態的一致性。
3)隔離性:並發事務的修改必須與其他並發事務所做的修改隔離。一個事務執行時不可以看到另一個事務執行的中間階段。
4)持久性:事務提交或回滾操作成功執行後,該結果對於系統的響應是永久的,無論之後發生任何事件。
--分類:根據數據庫中發生事件的邏輯功能的不同,可以使用不同類型的事務完成對數據庫中數據的維護。事務可以分顯式事務、隱式事務和自動提交事務三種類型。
1)自動提交事務。是數據庫的默認事務管理模式。每一個T-SQL語句都作為一個獨立的事務發生。如果語句成功執行,則提交該語句;如果執行遇到錯誤,則回滾該語句。只要沒有聲明顯式事務或隱式事務,那麼數據庫的實際連接就此默認模式操作。
2)隱式事務。指不需要描述事務的開始,只需要指明何時提交或回滾事務即可。若想使用隱式事務,可以使用set implicit_transaction on語句開啟隱式事務模式,在隱式事務使用完畢後,再用set implicit_transaction off語句關閉隱式事務模式即可。當隱式事務模式開啟後,首次執行以下任何語句時,都會自動啟動一個事務:create、alter、drop、select、insert、update、delete、truncate、open、fetch、grant、revoke。在發生COMMIT或ROLLBACK語句之前,該事務將一直保持有效。在第一個事務被提交或回滾之後,下次當連接執行以上任何語句時,數據庫引擎實例都將自動啟動一個新事務。該模式將不斷的生成隱性事務鏈,直到隱式事務模式關閉為止。
3)顯式事務。指表明了事物的開始和結束的事務。事務以beigin transaction語句開始,以commit transaction或rollback transaction語句結束。
--事務的操作流程
顯式事務的主要操作流程:
1)開始事務:begin transaction [事務名稱]
--使用該語句標識一個事務的開始,全局變量@@transaction的值遞增1,可以用來判斷事務執行的結果狀態。允許開始事務是不指定事務名稱。transaction可簡寫為tran。
2)提交事務:commit transaction [事務名稱]
--如果事務中的語句執行時沒有遇到錯誤,可以使用該語句成功提交事務。事務中對數據庫的操作有效執行,事務占有的資源被釋放。可以不指定事務名稱,以提交與之配對的begin transaction開始的事務。transaction可簡寫為tran。
3)回滾事務:rollback transaction [事務名稱]
--如果事務中的語句執行時遇到錯誤,可以使用該語句清除遇到的事務,所有數據返回到事務開始時的狀態。事務占用的資源被釋放。可以不指定事務名稱,以回滾與之配對的begin transaction開始的事務。transaction可簡寫為tran。
例1:(***下面是一個幫助理解的案例***) 在“賬戶表”中完成從張三賬戶中轉出100元到道李四賬戶的轉賬操作,要求賬戶不能透支。如果產生透支的情況,打印“轉賬失敗!”的錯誤提示,同時撤銷轉賬事件;如果轉賬操作沒有錯誤,打印出“轉賬成功!”提示,同時顯示轉賬後信息。 "賬戶表"轉賬前 "賬戶表"轉賬後 ────┬──── ────┬──── 姓名 余額 姓名 余額 ────┼──── ────┼──── 張三 1100 張三 100 ────┼──── ────┼──── 李四 200 李四 1200 ────┴──── ────┴──── 分析:為避免賬戶余額透支,為“余額”字段設置check約束“余額>=0”,執行從張三賬戶轉出金額給李四的操作實質是修改:賬戶表:,給張三金額減1000元,給李四金額加1000元。 可以把修改操作封裝到事務中,再通過判斷修改操作是否存在錯誤,決定事務提交或回滾。 set nocount on print '=====轉賬前金額=====' select*from賬戶表 go begin tran --開始事務 declare @serror int set @serror=0 update 賬戶表 set 余額=余額-1000 where 姓名='張三' set @serror=@serror+@@ERROR --全局變量用來統計最後一次T-SQL語句操作是否有誤,如有返回錯誤代碼,如無返回0。 update 賬戶表 set 余額=余額+1000 where 姓名='李四' set @serror=@serror+@@ERROR if @serror<>0 begin rollback tran --回滾事務 print '轉賬失敗!' end else begin commit tran --提交事務 print '轉賬成功!' end go print '=====轉賬後金額=====' select*from 賬戶表 go set nocount off 附:("賬戶表"數據庫 T-SQl語句) --建立"賬戶表"數據庫-- create database 賬戶表 on(name='賬戶表_m', filename='D:\賬戶表_m.mdf', size=3mb,filegrowth=1mb,maxsize=unlimited) log on(name='賬戶表_l', filename='D:\賬戶表_l.ldf', size=1,filegrowth=10%,maxsize=unlimited) go --為數據庫"賬戶表"建立數據表"賬戶表" use 賬戶表 go create table 賬戶表 (姓名 nvarchar(5)not null primary key, 余額 decimal(18, 0)not null ) --為數據表"賬戶表"添加數據 insert 賬戶表 values('張三',1100) insert 賬戶表 values('李四',200) --為數據表“賬戶表”設置檢查約束 alter table 賬戶表 add constraint CK_賬戶表_余額 --添加約束 check (余額>=0) 例2:(從“商品管理數據庫”的“客戶信息表”中刪除客戶編號為20130001的客戶記錄。刪除後給出提示信息,並顯示刪除後的“客戶信息表”中的記錄) use 商品管理數據庫 go set nocount on print '=====原客戶信息表=====' select*from 客戶信息表 go begin tran declare @serror int set @serror=0 delete 客戶信息表 where 客戶編號='20130001' set @serror=@serror+@@ERROR if @serror<>0 begin rollback tran print '刪除客戶失敗!' end else begin commit tran print '刪除客戶成功!' end go print '=====原客戶信息表=====' select*from 客戶信息表 go set nocount off理解例子
--鎖--
SQL Server中的鎖用來控制一個事務與另一個事務並發性。系統會自動為被訪問的資源設置或釋放鎖。
如果某個事務已鎖定一個資源,而另一個事務要訪問該資源,那麼SQL Server會根據第一個事務所使用的鎖模式的兼容性來確定是否授予第二個鎖。
資源的鎖定模式可分為: 意向共享(IS)、共享(S)、更新(U)、意向排他(IX)、意向排他共享(SIX)和排他(X)六種模式。
常用鎖模式矩陣:
請求的鎖模式 IS S U IX SIX X IS YES YES YES YES YES NO S YES YES YES NO NO NO U YES YES NO NO NO NO IX YES NO NO YES NO NO SIX YES NO NO NO NO NO X NO NO NO NO NO NO
Microsoft SQL Server 中完整的鎖兼容性矩陣:(參考)
死鎖現象:在多個任務中,如果一個任務鎖定了其他任務試圖鎖定的資源,此時會造成任務的永久阻塞,從而出現死鎖現象。
除非某個外部進程斷開死鎖,否則死鎖中的兩個事務都將無限期等待下去。
注:"--"可看成說明或者注釋文本