資料庫學習之旅——實驗8
阿新 • • 發佈:2019-01-03
本節介紹資料庫事務中的SQL SERVER 事務的定義
本實驗的目的:熟悉SQL SERVER 的事務控制語言,能夠熟練使用事務控制語言來編寫事務處理程式。
事務的原理解析:
1.事務的概念:
事務(TRANSACTION)是一組單一邏輯工作單元的操作集合,是採用高階資料操縱語言或程式語言書寫的使用者程式 ,並由事務開始BEGIN TRANSACTION 和事務結束END TRANSACTION 來界定全體操作的集合。
2.事務的性質::
資料庫管理系統為了實現資料庫系統的完整性,事務的ACID性質是資料庫事務處理的基礎,具有如下性質。
原子性:要求事務的全部操作要麼在資料庫中 全部正確地反映出來,要麼全部不反映。
一致性:資料庫中資料不因事務的執行而受到破壞,事務執行的結果應當使得資料庫由一種一致性達到另一種 新的一致性。資料的一致性保證資料庫的完整性。
隔離性:事務的併發執行與這些事務單獨執行的結果一樣。在多個事務併發時,各個事務不必關心其他事務的執行,如同在單個使用者環境下執行一樣。事務的隔離性是事務併發控制技術的基礎。
永續性:事務對資料庫的更新應永久的反映在資料庫中。一個事務一旦完成其全部操作之後,對資料庫所有更新操作的結果將在資料庫中永久存在,及時以後發生故障也應保留這個事務的執行結果。永續性的意義在於保證資料庫具有可恢復性。
以下是本次實驗的練習與習題答案:(school表在此並未發出,請參考之前的練習)
USE SCHOOL
--4.1.4實驗練習
--假設學校將學生的銀行卡 和校園卡進行了繫結,允許學生直接從銀行卡轉賬到校園卡中。假設某學號為05212222的學生需要從銀行卡中轉賬100元到校園卡中,編寫事務處理程式,實現這一操作。
--(1)採用隱式事務方式來實現事務程式設計。
UPDATE ICBC_CARD
SET RESTORED_MONEY = RESTORED_MONEY-100
WHERE STU_CARD_ID = '05212222'
UPDATE STU_CARD
SET REMAINED_MONEY = REMAINED_MONEY+100
WHERE CARD_ID = '05212222'
--*****注:以上的程式碼中採取隱式事務方法,如果對該學生的銀行卡資料更新成功,會自動向資料庫提交。假若後來對該學生 校園卡的資料更新未能成功,則會造成轉賬失敗,但前一操作已經提交,無法還原。這就可能造成對資料庫狀態與事實語義不一致。
--*****注:針對以上問題,需要設法將這若干條SQL語句組合成一個獨立的事務,這樣才能保證各個操作步驟要麼同時成功,要麼一起失敗。這就需要在之後的(2)中的顯式事務方法來處理該事務。
--(2)採用顯式事務使用者定義事務的方法來實現事務程式設計。
BEGIN TRAN
UPDATE ICBC_CARD
SET RESTORED_MONEY = RESTORED_MONEY-100
WHERE STU_CARD_ID = '05212222'
UPDATE STU_CARD
SET REMAINED_MONEY = REMAINED_MONEY+100
WHERE CARD_ID = '05212222'
COMMIT TRAN
--*****注:為了完全控制事務並定義多個操作步驟組成的邏輯工作單元,可以採用顯式使用者定義事務的方式來實現使用者期望的邏輯操作。
--(3)事務與批命令。
UPDATE COURSES SET HOUR = 96 WHERE CID = '10001'
INSERT TEACHERS VALUES('1234567890','MY',' [email protected]',3000)
SELECT TOP 10 * FROM TEACHERS(HOLDLOCK)
GO
--*****注:批處理是由一條或多條TRANSACT SQL 語句或命令組成,能夠成組的執行,用於向SQL SERVER 提交成組的TRANSACT SQL 的語句組,由GO語句來終止語句組。批處理經過整體編譯一次成為一個執行計劃,並一次將整個執行計劃執行完畢。
--*****注:出發皮命令沒有固有的事務性質,除顯式的定義由幾個語句構成的單個事務,否則批命令中的每條語句都是一個互相獨立的事務,每條語句單獨完成或單獨失敗,而且批命令中的一個事務失敗,不影響其他語句的執行。
--(4)巢狀事務的程式設計。
SELECT 'BEFORE TRANSACTION: ' AS HINT,@@TRANCOUNT AS TRANACTIONCOUNT
BEGIN TRAN
SELECT 'THE FIRST TRANSACTION STARTS: ' AS HINT,@@TRANCOUNT AS TRANACTIONCOUNT
SELECT TOP 3 * FROM CHOICES
BEGIN TRAN
SELECT 'THE SECOND TRANSACTION STARTS: ' AS HINT,@@TRANCOUNT AS TRANACTIONCOUNT
COMMIT TRAN
SELECT 'THE SECOND TRANSACTION COMMITS: ' AS HINT,@@TRANCOUNT AS TRANACTIONCOUNT
ROLLBACK TRAN
SELECT 'THE FIRST TRANSACTION ROLLBACK: ' AS HINT,@@TRANCOUNT AS TRANACTIONCOUNT
--*****注:巢狀事務主要是為了支援儲存過程中的一些事務,這些事務可以從事務中已有的程序中呼叫,也可以從沒有活動的事務程序中呼叫。巢狀事務隊伍COMMIT TRANSACTION語句的每個呼叫都對應 於最後執行的BEGIN TRANSACTION 語句,也就是最內層的事務。
--(5)在儲存過程、觸發器中使用事務程式設計。
CREATE TRIGGER TD_COURSE ON COURSES
FOR DELETE
AS
DECLARE @INFO VARCHAR(255)
SELECT @INFO = '觸發器中的事務資料為: ' +CONVERT(VARCHAR(2),@@TRANCOUNT)
PRINT @INFO
RETURN
--*****注:觸發器是一種特殊型別的儲存過程,主要用於完成 資料庫中物件的完整性。在表中進行資料修改時自動執行,觸發器被視為執行資料修改事務的一部分,與資料修改語句在同一事務空間中執行。由於觸發器已經在事務情景中操作,因此事務中要的事務控制語句只有ROLLBACK或者SAVE TRAN,不需要發出BEGIN TRAN。
PRINT '刪除操作以前觸發器中的事務數為: ' +CONVERT(VARCHAR(2),@@TRANCOUNT);
DELETE FROM COURSES
WHERE CID = '10052'
PRINT '刪除操作之後觸發器中的事務數為: ' +CONVERT(VARCHAR(2),@@TRANCOUNT);
--*****注:以上程式碼為COURSES的刪除操作,建立一個觸發器,然後執行一個刪除操作,觀察事務數目的變化。在刪除操作執行的過程中,觸發器得到執行,而且事務的數目為1,這就驗證了是觸發器事務是資料修改事務的一部分。
CREATE PROCEDURE INSERTCOURSEINFO
@COURSEID CHAR(10),
@COURSENAME VARCHAR(30),
@HOUR INT,
@RETURNSTRING VARCHAR(100)
AS
BEGIN TRAN
IF EXISTS(SELECT CID FROM COURSES WHERE CID = @COURSEID)
BEGIN
SELECT @RETURNSTRING = '課程資訊已經存在'
GOTO ONERROR
END
--新增課程資訊
INSERT INTO COURSES VALUES(@COURSEID,@COURSENAME,@HOUR)
IF @@ERROR<>0
BEGIN
SELECT @RETURNSTRING = '新增課程資訊失敗'
GOTO ONERROR
END
SELECT @RETURNSTRING = '新增課程資訊成功'
COMMIT TRAN
--錯誤處理
ONERROR:
ROLLBACK TRAN
--*****注:同樣以上程式碼為從事務中呼叫儲存的過程,也可以在儲存過程中啟動事務,而且這是經常在資料庫開發過程中應用到的。因為在儲存過程中使用事務,可以提高資料庫操作的效率,可以方便維護。
--(6)命令事務與事務儲存點。
--方法①:
BEGIN TRAN TRAN_UPD_COURSES
UPDATE COURSES
SET HOUR = 60
WHERE CID = '10052'
BEGIN TRAN TRAN_UPD_TEACHERS
INSERT INTO TEACHERS
VALUES('1234567890','ZS','[email protected]',3000)
IF @@ERROR!=0
BEGIN
--撤銷事務
ROLLBACK TRAN TRAN_UPD_TEACHERS
PRINT '更新教師表失敗'
RETURN
END
--提交內層事務
COMMIT TRAN TRAN_UPD_TEACHERS
--提交外層事務
COMMIT TRAN TRAN_UPD_COURSES
--*****注:在編寫大的儲存過程、唱的批處理,以及大量事務巢狀的時候,一個常見的問題就是程式碼的可讀性差。為了改進程式碼的可讀性,在進行事務程式設計的時候,可以對事務進行命名清晰的標誌事務,提示使用者程式碼的邏輯性。
--*****注:命名事務是通過在BEGIN TRAN 語句中為事務命名,來標誌整個事務邏輯的工作單元。通過對事務命名,使得每個事務都易於識別,這對於事務巢狀更加重要。
--方法②:
BEGIN TRAN TRAN_UPD_COURSES
UPDATE COURSES
SET HOUR = 45
WHERE CID = '10052'
--設定事務儲存點
SAVE TRAN TRAN_UPD_COURSES_DONE
INSERT INTO TEACHERS
VALUES('1234567890','ZS','[email protected]',3000)
IF @@ERROR!=0 OR @@ROWCOUNT>1
BEGIN
--撤銷事務
ROLLBACK TRAN TRAN_UPD_TEACHERS_DONE
PRINT '更新教師表資訊失敗!'
RETURN
END
--提交事務
COMMIT TRAN TRAN_UPD_COURSE
--*****注:此方法是事務儲存點,事務儲存點提供一種在事務中標記用ROLLBACK撤銷事務工作點的方法。利用事務儲存點,可提交事務開始處至儲存點的部分事務,而將事務的其他部分撤銷。
執行結果請讀者自試。