一、SQL Server聯(lián)機叢書(shū)中關(guān)于事務(wù)的定義
事務(wù)
事務(wù)是作為單個(gè)邏輯工作單元執行的一系列操作。一個(gè)邏輯工作單元必須有四個(gè)屬性,稱(chēng)為 ACID(原子性、一致性、隔離性和持久性)屬性,只有這樣才能成為一個(gè)事務(wù):
原子性
事務(wù)必須是原子工作單元;對于其數據修改,要么全都執行,要么全都不執行。
一致性
事務(wù)在完成時(shí),必須使所有的數據都保持一致?tīng)顟B(tài)。在相關(guān)數據庫中,所有規則都必須應用于事務(wù)的修改,以保持所有數據的完整性。事務(wù)結束時(shí),所有的內部數據結構(如 B 樹(shù)索引或雙向鏈表)都必須是正確的。
隔離性
由并發(fā)事務(wù)所作的修改必須與任何其它并發(fā)事務(wù)所作的修改隔離。事務(wù)查看數據時(shí)數據所處的狀態(tài),要么是另一并發(fā)事務(wù)修改它之前的狀態(tài),要么是另一事務(wù)修改它之后的狀態(tài),事務(wù)不會(huì )查看中間狀態(tài)的數據。這稱(chēng)為可串行性,因為它能夠重新裝載起始數據,并且重播一系列事務(wù),以使數據結束時(shí)的狀態(tài)與原始事務(wù)執行的狀態(tài)相同。
持久性
事務(wù)完成之后,它對于系統的影響是永久性的。該修改即使出現系統故障也將一直保持。
指定和強制事務(wù)處理
SQL 程序員要負責啟動(dòng)和結束事務(wù),同時(shí)強制保持數據的邏輯一致性。程序員必須定義數據修改的順序,使數據相對于其組織的業(yè)務(wù)規則保持一致。然后,程序員將這些修改語(yǔ)句包括到一個(gè)事務(wù)中,使 Microsoft® SQL Server™ 能夠強制該事務(wù)的物理完整性。
企業(yè)數據庫系統(如 SQL Server)有責任提供一種機制,保證每個(gè)事務(wù)物理的完整性。SQL Server 提供:
鎖定設備,使事務(wù)相互隔離。
記錄設備,保證事務(wù)的持久性。即使服務(wù)器硬件、操作系統或 SQL Server 自身出現故障,SQL Server 也可以在重新啟動(dòng)時(shí)使用事務(wù)日志,將所有未完成的事務(wù)自動(dòng)地回滾到系統出現故障的位置。
事務(wù)管理特性,強制保持事務(wù)的原子性和一致性。事務(wù)啟動(dòng)之后,就必須成功完成,否則 SQL Server 將撤消該事務(wù)啟動(dòng)之后對數據所作的所有修改。
©1988-2000 Microsoft Corporation。保留所有權利。
二、實(shí)例
①、利用ASP內置ADO組件中的Connection對象可以實(shí)現對數據庫操作的事務(wù)性處理。
Connection 對象中的事務(wù)進(jìn)程:
- BeginTrans - 開(kāi)始新事務(wù)。
- CommitTrans - 保存任何更改并結束當前事務(wù)。它也可能啟動(dòng)新事務(wù)。
- RollbackTrans - 取消當前事務(wù)中所作的任何更改并結束事務(wù)。它也可能啟動(dòng)新事務(wù)。
<%
Call DBConnection(objConn)‘//鏈接數據庫
On Error Resume Next
objConn.BeginTrans ‘//啟動(dòng)一個(gè)事務(wù)
‘//語(yǔ)句一
strSql = "Insert Into [User] (UName, UPasswd) Values (‘"& s_uname &"‘, ‘"& s_upasswd &"‘)"
objConn.Execute(strSql)
‘//語(yǔ)句二
strSql = "Insert Into UserInfo (UName, Age, Sex, TelPhone, Address) Values (‘"& s_uname &"‘, "& i_age &", ‘"& s_sex &"‘, ‘"& s_telphone &"‘, ‘"& s_address &"‘)"
objConn.Execute(strSql)
If objConn.Errors.Count Then
Errors.Clear
objConn.RollBackTrans‘//如果有錯誤,則事務(wù)向前回滾
Response.Write("Fail")
Else
objConn.CommitTrans ‘//提交一個(gè)事務(wù)
Response.Write("OK")
End If
Call DBClose(objConn)‘//釋放數據庫鏈接
%>
注意:
以上代碼在語(yǔ)句一遇到錯誤時(shí)將不能進(jìn)行正常的事務(wù)處理,語(yǔ)句一將得不到執行。因為用到了On Error Resume Next所以objConn.Errors.Count只能獲得最后一個(gè)數據庫操作的objConn返回的結果,但是因為語(yǔ)句二是正確的,所以此事務(wù)處理就無(wú)效了。那么就需要對出錯處理作出相對應的修改。
將If objConn.Errors.Count Then改為If Err Then
②、利用數據庫系統自身的事務(wù)處理機制,通過(guò)在數據庫服務(wù)器中編寫(xiě)包含事務(wù)的存儲過(guò)程,完成對數據操作的事務(wù)處理。同時(shí),利用ADO組件調用存儲過(guò)程,根據存儲過(guò)程的返回代碼判斷事務(wù)處理是否執行成功。
在數據庫系統中,每一條SQL語(yǔ)句都是一個(gè)事務(wù)。因此可以保證每條語(yǔ)句要么完成,要么退回到開(kāi)始之處。但是如果希望一組SQL語(yǔ)句的操作要么全部完成,要么全部無(wú)效,就需要利用數據庫的事務(wù)處理機制來(lái)實(shí)現。
在數據庫中生成存儲過(guò)程的主要代碼如下:
CREATE Procedure dbo.RegisterUser
@UName varchar(30),
@UPasswd varchar(30),
@Age Int,
@Sex varchar(6),
@TelPhone varchar(20),
@Address varchar(50)
as
Set nocount ON
Begin
Begin Transaction
Insert Into dbo.[User] (UName, UPasswd) Values (@UName, @UPasswd)
If @@Error <> 0
Begin
/*操作失敗,事務(wù)回滾*/
RollBack Transaction
/*返回存儲過(guò)程,并設置返回碼為事務(wù)操作失敗*/
Return -1
End
Insert Into dbo.[UserInfo] (UName, Age, Sex, TelPhone, Address) Values (@UName, @Age, @Sex, @TelPhone, @Address)
If @@Error <> 0
Begin
/*操作失敗,事務(wù)回滾*/
RollBack Transaction
Return -1
End
/*如果操作執行正確,則提交事務(wù)*/
Commit Transaction
Return 0
End
GO
在A(yíng)SP腳本中調用數據庫存儲過(guò)程的主要代碼如下:
Call DBConnection(objConn)‘//鏈接數據庫
Set MyComm = Server.CreateObject("ADODB.Command")
MyComm.ActiveConnection = objConn ‘objConn是數據庫連接對象
MyComm.CommandText = "RegisterUser" ‘指定存儲過(guò)程名
MyComm.CommandType = 4 ‘表明這是一個(gè)存儲過(guò)程
MyComm.Prepared = True ‘要求將SQL命令先行編譯
‘聲明存儲過(guò)程返回值
MyComm.Parameters.Append MyComm.CreateParameter("RetCode",2,4)
‘//創(chuàng )建存儲過(guò)程輸入參數對象
MyComm.Parameters.append MyComm.CreateParameter("@UName",200,1,30,s_uname)
MyComm.Parameters.append MyComm.CreateParameter("@UPasswd",200,1,30,s_upasswd)
MyComm.Parameters.append MyComm.CreateParameter("@Age",3,1,4,i_age)
MyComm.Parameters.append MyComm.CreateParameter("@Sex",200,1,6,i_sex)
MyComm.Parameters.append MyComm.CreateParameter("@TelPhone",200,1,20,s_telphone)
MyComm.Parameters.append MyComm.CreateParameter("@Address",200,1,50,s_address)
MyComm.Execute
RetValue = CInt(MyComm("RetCode"))
‘//根據返回值判斷注冊是否成功
If RetValue < 0 Then
Response.Write("Fail")
Else
Response.Write("OK")
End If
Set MyComm = Nothing
Call DBClose(objConn)‘//釋放數據庫鏈接
③、利用MTS(Microsoft Transaction Server)組件的事務(wù)處理機制實(shí)現事務(wù)處理時(shí),需要特別注意的是,這種機制下的事務(wù)不能跨越多個(gè)ASP頁(yè),如果一個(gè)事務(wù)處理需要來(lái)自多個(gè)組件的對象,則須將對這些對象的操作組合在一個(gè)ASP頁(yè)中。
首先需要在頁(yè)首添加指令@TRANSACTION,將一個(gè)ASP頁(yè)面聲明為事務(wù)性。
@TRANSACTION指令必須在一頁(yè)中的第一行,否則將產(chǎn)生錯誤。當頁(yè)面中ASP腳本處理結束時(shí),當前事務(wù)即告結束。
<%@Transaction = "Required" Language="VBScript"%>
<%
On Error Resume Next
‘//事務(wù)執行成功觸發(fā)事件
Sub OnTransactionCommit()
Response.Write("OK")
End Sub
‘//事務(wù)執行失敗觸發(fā)事件
Sub OnTransactionAbort()
Response.Write("Fail")
End Sub
Call DBConnection(objConn)‘//鏈接數據庫
strSql = "Insert Into [User] (UName, UPasswd) Values (‘"& s_uname &"‘, ‘"& s_upasswd &"‘)"
objConn.Execute(strSql)
strSql = "Insert Into UserInfo (UName, Age, Sex, TelPhone, Address) Values (‘"& s_uname &"‘, "& i_age &", ‘"& s_sex &"‘, ‘"& s_telphone &"‘, ‘"& s_address &"‘)"
objConn.Execute(strSql)
If Err Then
Err.Clear
ObjectContext.SetAbort()
Else
ObjectContext.SetComplete()
End If
Call DBClose(objConn)‘//釋放數據庫鏈接
%>
方案比較 :
從靈活的角度考慮,選擇采用ASP數據庫組件的方法具有一定的優(yōu)勢:既可以選用ADO數據庫組件完成事務(wù)處理,同時(shí)還可以根據實(shí)際需要,定制自己的數據庫組件(只要滿(mǎn)足ASP組件編寫(xiě)規范即可)。
如果從數據庫事務(wù)處理的可靠性等角度考慮,則采用數據庫內部的事務(wù)處理存儲過(guò)程更好。這樣可以直接利用數據庫事務(wù)機制完成應用程序的邏輯事務(wù)處理,安全可靠,并且減少了Web服務(wù)器與數據庫服務(wù)器之間的數據交互。這一點(diǎn)對分布式數據庫系統尤為重要。
采用MTS組件的事務(wù)處理方法的優(yōu)勢在于:由MTS服務(wù)器直接控制和管理組件(在MTS中注冊的組件)操作的完成和撤消,具有良好的擴展空間和應用前景,可以充分發(fā)揮MTS的技術(shù)優(yōu)勢,增強網(wǎng)絡(luò )應用的容錯性能,提高IIS Web服務(wù)器的動(dòng)態(tài)性能。