《SQL Server 2008從入門到精通》--20180724


1.事務

事務在SQL Server中相當於一個工作單元,可以確保同時發生的行為與數據的有效性不發生沖突,並且維護數據的完整性。在實際應用中,多個用戶在同一時刻對同一部分數據進行操作時,可能會由於一個用戶的操作使其他用戶的操作和數據失效。事務可以很好地解決這一點。事務總是確保數據庫的完整性。

1.1.事務的ACID屬性

  • 原子性(Atomicity):事務是工作單元。事務內的所有工作要不全部完成,要不全部沒完成,不存在完成一部分的說法。
  • 一致性(Consistency):事務完成時,所有的數據都必須是一致的。事務結束時,所有內部數據結構都必須是正確的。
  • 隔離性(Isolation):由並發事務所做的修改必須與其他並發事務所做的修改隔離。事務識別數據時數據所處的狀態,要不是另一並發事務修改前的狀態,要不是另一並發事務修改后的狀態,不存在中間狀態。
  • 持久性(Durability):事務提交后,事務所完成的工作結果會得到永久保存。

示例1:情況如下2個代碼

--語句1:
UPDATE student
SET stu_birthday='1993-02-01',
stu_native_place='山西',
stu_phone='15729810290'
WHERE stu_no='20180101'
--語句2:
UPDATE student
SET stu_birthday='1993-02-01'
WHERE stu_no='20180101'
UPDATE student
SET stu_native_place='山西'
WHERE stu_no='20180101'
UPDATE student
SET stu_phone='15729810290'
WHERE stu_no='20180101'

在語句1中,只有一個事務,對列的更新要不全部成功更新,要不全部更新失敗。而語句2中,有三個事務,就算其中有某個列更新失敗,也不會影響其他列的更新。

1.2.事務分類

1.2.1.系統提供的事務

系統提供的事務是指執行某些T-SQL語句時,一條語句段構成了一個事務,如ALTER TABLE,CREATE,DELETE,DROP,FETCH等。

1.2.2.用戶自定義的事務

實際應用中,經常使用用戶自定義的事務。自定義的方法是,以BEGIN TRANSACTION開始,以COMMIT TRANSACTION或ROLLBACK TRANSACTION結束。這兩個語句之間所有語句都被視為一體。
示例2:自定義事務的應用

BEGIN TRANSACTION
INSERT INTO student(stu_no,stu_name,stu_birthday,stu_enter_score)
VALUES('20180013','賈乃亮','1993-01-20','498')
INSERT INTO student(stu_no,stu_name,stu_birthday,stu_enter_score)
VALUES('20180014','周星星','1993-07-20','532')
INSERT INTO student(stu_no,stu_name,stu_birthday,stu_enter_score)
VALUES('20180015','雨化田','錯誤格式數據','570')
INSERT INTO student(stu_no,stu_name,stu_birthday,stu_enter_score)
VALUES('20180016','周琪','1993-01-20','653')
INSERT INTO student(stu_no,stu_name,stu_birthday,stu_enter_score)
VALUES('20180017','陳璐','1998-01-20','599')
COMMIT TRANSACTION

在上面的事務中,第三條插入數據是錯誤數據,無法成功插入,執行上面的語句,發現所有插入語句都沒有被執行成功。
還有一種用戶自定義事務——分布式事務。如果在比較復雜的環境中,有多台服務器,為了保證服務器中數據的完整性和一致性,就必須定義一個分布式事務。舉個例子,有2台服務器,一台存放庫存數據,另一台存放訂單數據,用戶下單的邏輯是,下單前先扣除庫存數據,再下單。如果沒有分布式事務,容易出現扣除庫存數量,單下單卻沒成功,造成兩個數據庫數據不一致的情況。

1.3.管理事務

主要使用以下4條語句管理事務:BEGIN TRANSACTION,COMMIT TRANSACTION,ROLLBACK TRANSACTION和SAVE TRANSACTION。此外還有2個全局變量可以用在事務處理語句中:@@ERROR和@@TRANCOUNT。
BEGIN TRANSACTION,COMMIT TRANSACTION,ROLLBACK TRANSACTION不多說了。

1.3.1.SAVE TRANSACTION

允許部分地提交一個事務,同時仍能回退這個事務的剩余部分。
示例3:BEGIN TRANSACTION,COMMIT TRANSACTION,ROLLBACK TRANSACTION和SAVE TRANSACTION的結合使用
執行下列語句

BEGIN TRANSACTION changed
INSERT INTO student(stu_no,stu_name,stu_sex,stu_enter_score)
VALUES('20180014','譚晶','男','533')
SAVE TRANSACTION saveinsert--設置保存事務點saveinsert
UPDATE student
SET stu_sex='錯誤數據'
WHERE stu_no='20180014'
ROLLBACK TRANSACTION saveinsert--回滾到保存事務點saveinsert
COMMIT TRANSACTION changed

上述代碼完成了一個這樣的功能:設置一個事務,事務名changed,該事務的作用是向student表中插入一條記錄並更新該記錄的stu_sex字段。如果更新失敗,則回滾到插入操作,即保證不管更新是否成功,插入操作都能成功。

1.3.2.@@TRANCOUNT變量和@@ERROR變量

@@TRANCOUNT變量報告當前嵌套事務為第幾層嵌套,每個BEGIN TRANSACTION都能使@@TRANCOUNT加一,@@ERROR變量用來保存任何一條T-SQL語句的最新錯誤號。
示例4:對示例3中代碼加上對@@TRANCOUNT和@@ERROR變量的訪問
執行下列語句

BEGIN TRANSACTION changed
SELECT @@TRANCOUNT AS trancount
INSERT INTO student(stu_no,stu_name,stu_sex,stu_enter_score)
VALUES('20180016','陳甜甜','女','661')
SAVE TRANSACTION saveinsert--設置保存事務點saveinsert
UPDATE student
SET stu_sex='錯誤數據'
WHERE stu_no='20180016'
SELECT @@ERROR AS error
ROLLBACK TRANSACTION saveinsert--回滾到保存事務點saveinsert
COMMIT TRANSACTION changed
GO

結果如圖所示

示例5:對@@TRANCOUNT變量的理解
執行下列語句

BEGIN TRANSACTION changed1
SELECT @@TRANCOUNT AS trancount
INSERT INTO class(class_id,class_name,enter_score_level)
VALUES('07','TEST','TEST')
BEGIN TRANSACTION changed2
INSERT INTO class(class_id,class_name,enter_score_level)
VALUES('08','TEST','TEST')
BEGIN TRANSACTION changed3
SELECT @@TRANCOUNT AS trancount
INSERT INTO class(class_id,class_name,enter_score_level)
VALUES('09','TEST','TEST')
COMMIT TRANSACTION changed3
COMMIT TRANSACTION changed2
COMMIT TRANSACTION changed1

我在changed1和changed3中對@@TRANCOUNT變量進行了訪問,結果如圖所示

每個BEGIN TRANSACTION都使@@TRANCOUNT加一。

1.4.SQL Server本地事務支持

應用程序主要通過設置事務開始時間和事務結束時間來管理事務。這可以通過函數或者應用程序接口(API)實現。默認情況下,事務按連接級別進行處理,使用API函數或者SQL語句,可以將事務作為顯式,隱式和自動提交事務來處理。

1.4.1.自動提交事務模式

自動提交事務模式是SQL Server默認的事務管理模式,每個SQL語句都是一個事務,在完成時都會被提交或回滾。在自動提交事務模式下,當遇到的錯誤是編譯時錯誤,會回滾整個批處理,當遇到的錯誤是運行時錯誤,不會回滾整個批處理,而是執行部分語句並提交。
示例6:遇到編譯時錯誤和運行時錯誤時,事務處理方式是不同的
執行下列語句

--編譯時錯誤代碼
USE test
GO
CREATE TABLE T1(
id INT NOT NULL,
name VARCHAR(20),
age INT,
CONSTRAINT pk_id PRIMARY KEY(id)
)
GO
INSERT INTO T1(id,name,age)VALUES
('1001','宋佳佳','26')
INSERT INTO T1(id,name,age)VALUES
('1002','陳琦','23')
INSERT INTO T1(id,name,age)VALUE
('1003','盧哲','27')--語法錯誤,回滾整個批處理
GO
SELECT * FROM T1

結果可以看到,T1表雖然被創建了,但是三條數據都沒有插入成功。可見編譯時錯誤會回滾整個批處理。
刪除T1表后執行下列語句

--運行時錯誤代碼
USE test
GO
CREATE TABLE T1(
id INT NOT NULL,
name VARCHAR(20),
age INT,
CONSTRAINT pk_id PRIMARY KEY(id)
)
GO
INSERT INTO T1(id,name,age)VALUES
('1001','宋佳佳','26')
INSERT INTO T1(id,name,age)VALUES
('1002','陳琦','23')
INSERT INTO T1(id,name,age)VALUES
('1001','盧哲','27')--主鍵重復錯誤,僅該語句不執行
GO
SELECT * FROM T1

結果如圖所示

僅錯誤的INSERT語句不執行,而整個批處理並沒有回滾。可見運行時錯誤不會導致整個批處理被回滾,僅僅只是中斷執行。

1.4.2.顯式事務模式

有明顯使用BEGIN TRANSACTION語句定義一個事務的就是顯式事務模式。示例2,3,4,5都是顯式事務模式。

1.4.3.隱式事務模式

隱式事務模式是一種連接選項,在該選項下每個連接執行的SQL語句都被視為單獨的事務。當連接以隱式事務模式進行操作時,SQL Server將在事務提交或事務回滾后自動開始新事務。隱式事務模式無需BEGIN TRANSACTION這種語句來進行定義。

1.4.3.1.通過SET IMPLICIT_TRANSACTIONS ON語句設置隱式事務模式

顯式事務模式模式會在有大量DDL和DML語句執行時自動開始,並一直保持到用戶明確提交為止。也就是說,如果設置了隱式事務模式,而SQL語句中又有事務沒有明確提交,即使用COMMIT TRANSACTION語句提交,那么用戶斷開連接,或者關閉數據庫時,系統會詢問有未提交的事務,是否提交,如果選擇否,那么未提交的事務將會被回滾,下次連接時就不存在了。
示例7:執行下列語句

SET IMPLICIT_TRANSACTIONS ON
GO

USE test
CREATE TABLE T1(
id INT NOT NULL,
name VARCHAR(20),
age INT,
CONSTRAINT pk_id PRIMARY KEY(id)
)
INSERT INTO T1(id,name,age)VALUES
('1001','宋佳佳','26')
COMMIT TRANSACTION
INSERT INTO T1(id,name,age)VALUES
('1002','陳琦','23')
INSERT INTO T1(id,name,age)VALUES
('1003','盧哲','27')
SELECT * FROM T1

結果如圖所示

然后斷開連接,出現如下提示

如果選擇否的話,再次連接成功后SELECT T1表,結果如圖所示

會發現1002和1003的記錄都被回滾了,那是因為在插入的時候,這兩條語句的事務沒有COMMIT,只有第一條插入語句被提交了。這就是隱式事務模式。

1.4.3.2.調用API函數來設置隱式事務模式

用來設置隱式事務模式的API機制是ODBC和OLE DB(不能理解,不多說了)

1.4.4.批范圍的事務

該事務只適用於多個活動的結果集。在MARS會話中啟動的SQL顯式或隱式事務,將變成批范圍事務,當批處理完成時,如果批范圍事務還沒有被提交或回滾,SQL Server將自動對其進行回滾。

1.5.隔離級別

當多個線程都開啟事務來操作數據庫中的數據時,數據庫要能進行隔離操作,以確保各個線程獲取數據的准確性。如果沒有隔離操作,會出現以下幾種情況:

  • 臟讀:一個事務處理過程里讀取了另一個未提交的事務中的數據。

例如:A轉100塊錢給B,SQL語句如下

UPDATE acount
SET cash=cash+100
WHERE name='B'--此時A通知B
UPDATE acount
SET cash=cash-100
WHERE name='A'

執行完第一條語句時,A通知B,讓B確認是否到賬,B確認錢到賬(此時發生了臟讀),而后無論第二條SQL語句是否執行,只要事務沒有提交,所有操作都將回滾,B第二次查看時發現錢沒有到賬。

  • 不可重復讀:一個事務范圍內多次查詢某個數據,返回不同的值,這是因為該數據被另一個事務修改並提交了。臟讀和不可重復讀的區別在於,臟讀是讀取了另一個事務還未提交的數據,不可重復都是讀取了反復讀取了前一個事務提交了的數據
  • 幻讀:比如事務T1將表中某一列數據從1修改成2,同時T2事務插入一條數據,該列值仍然是1,那么用戶查詢時就會發現該表還有1列數據為1,未被T1事務修改。

1.5.1.四種隔離級別

  • 未提交讀(READ UNCOMMITTED):事務隔離的最低級別,可執行未提交讀和臟讀,任何情況都無法保證
  • 提交讀(READ COMMITTED):在讀取數據時控制共享鎖,避免臟讀,但無法避免不可重復讀和幻讀。它是SQL Server 2008的默認值。
  • 可重復讀(REPEATABLE READ):鎖定查詢過程中所有數據,防止用戶更新數據,避免了臟讀和不可重復讀的發生,無法避免幻讀。
  • 可串行讀(SERIALZABLE):在數據集上放置一個范圍鎖,防止其他用戶在事務完成之前更新數據或插入行,是事務隔離的最大限制級別,避免了臟讀,不可重復讀和幻讀的發生。

事務隔離級別越高,越能保證數據的一致性和完整性。

1.5.2.設置事務隔離級別

默認情況下,SQL Server 2008的事務隔離級別為提交讀。可通過SET TRANSACTION ISOLATION LEVEL來設置事務隔離級別。

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

1.6.分布式事務

對多個數據庫中的數據進行修改的事務,是分布式事務。這些數據庫可以是本地數據庫,也可以是其他鏈接服務器上的數據庫。
分布式事務由一個分布式事務協調程序(DTC)來控制,若想使用分布式事務,必須先啟動該服務。在分布式事務中用COMMIT TRANSACTION提交事務,數據庫會自動調用一個兩步提交協議:1.通知每個數據庫核實它們能夠提交該事務並保留資源。2.當每個相關數據庫通知SQL Server 2008可以隨時提交該事務后,SQL Server 2008通知相關數據庫提交該事務。如果有一個數據庫不能成功提交該事務,則SQL Server 2008會通知所有相關數據庫回滾該事務。

1.7.高級事務主題

  • 嵌套事務:顯式事務可以嵌套在存儲過程中
  • 事務保存點:提供了一種可以部分回滾事務的機制
  • 綁定會話:有利於在一個服務器上的多個會話之間的協調操作,允許一個或多個會話共享事務和鎖,並且可以使用同一個數據,不會有鎖的沖突

1.8.管理長時間運行的事務

1.8.1.查看長時間運行的事務

執行下列語句

SELECT * FROM sys.dm_tran_database_transactions

結果如圖所示

1.8.2.停止事務

停止事務可能必須運行KILL語句,使用該語句時要小心,特別是在運行重要的進程時。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM