關系數據庫SQL之可編程性事務

前言

前面關系數據庫SQL之可編程性函數(用戶自定義函數)一文提到關系型數據庫提供了可編程性的函數、存儲過程、事務、觸發(fā)器及游標,前文已介紹了函數、存儲過程,本文來介紹一下事務的使用。(還是以前面的銀行系統(tǒng)為例)

圖片來自網絡

概述

是指作為單個邏輯工作單元執(zhí)行的一系列操作,要么完全地執(zhí)行,要么完全地不執(zhí)行。
一個邏輯工作單元要成為事務,必須滿足所謂的ACID(原子性、一致性、隔離性和持久性)特性。

語法

開始事務:事務開始的位置,就是單個邏輯工作單元的開始。
回滾事務:就是將數據恢復至事務開始的狀態(tài),一般是不滿足條件或者是發(fā)生錯誤的時候執(zhí)行該操作。
提交事務:事務結束的位置,就是單個邏輯工作單元成功執(zhí)行后,改變數據狀態(tài)。

--開始事務
BEGIN TRAN[SACTION]
--回滾事務,TRAN[SACTION]可省略
ROLLBACK TRAN[SACTION]
--提交事務
COMMIT TRAN[SACTION]

--事務使用
BEGIN TRAN[SACTION]
--這里是SQL語句塊

上面的SQL語句塊,需要在適當的位置加上COMMIT TRAN[SACTION],如果需要回滾可以有ROLLBACK TRAN[SACTION]。

事務可以與存儲過程聯合使用。

特性

  • 原子性(Atomic)(Atomicity)

事務必須是原子工作單元;對于其數據修改,要么全都執(zhí)行,要么全都不執(zhí)行。通常,與某個事務關聯的操作具有共同的目標,并且是相互依賴的。如果系統(tǒng)只執(zhí)行這些操作的一個子集,則可能會破壞事務的總體目標。原子性消除了系統(tǒng)處理操作子集的可能性。

  • 一致性(Consistent)(Consistency)

事務在完成時,必須使所有的數據都保持一致狀態(tài)。在相關數據庫中,所有規(guī)則都必須應用于事務的修改,以保持所有數據的完整性。事務結束時,所有的內部數據結構(如 B 樹索引或雙向鏈表)都必須是正確的。某些維護一致性的責任由應用程序開發(fā)人員承擔,他們必須確保應用程序已強制所有已知的完整性約束。例如,當開發(fā)用于轉帳的應用程序時,應避免在轉帳過程中任意移動小數點。

  • 隔離性(Insulation)(Isolation)

由并發(fā)事務所作的修改必須與任何其它并發(fā)事務所作的修改隔離。事務查看數據時數據所處的狀態(tài),要么是另一并發(fā)事務修改它之前的狀態(tài),要么是另一事務修改它之后的狀態(tài),事務不會查看中間狀態(tài)的數據。這稱為隔離性,因為它能夠重新裝載起始數據,并且重播一系列事務,以使數據結束時的狀態(tài)與原始事務執(zhí)行的狀態(tài)相同。當事務可序列化時將獲得最高的隔離級別。在此級別上,從一組可并行執(zhí)行的事務獲得的結果與通過連續(xù)運行每個事務所獲得的結果相同。由于高度隔離會限制可并行執(zhí)行的事務數,所以一些應用程序降低隔離級別以換取更大的吞吐量。

  • 持久性(Duration)(Durability)

事務完成之后,它對于系統(tǒng)的影響是永久性的。該修改即使出現致命的系統(tǒng)故障也將一直保持。

示例

  1. 創(chuàng)建一個帶事務的存儲過程:孫悟空要取錢,交易信息表里面插入交易信息,同時要更改賬戶表里面的余額
begin transaction
    if exists(select * from sysobjects where name = 'proc_getMoney')
    drop procedure proc_getMoney
    go
    create proc proc_getMoney
        @cardId varchar(19),
        @tranMoney money
    as
    declare @balance money
    select @balance = LeftMoney from CardInfo where CardID = @cardId
    if(@tranMoney <= @balance)
    begin
        insert into TransInfo values(@cardId,'取款',@tranMoney,default)
        if(@@ERROR=0)
        begin
            update CardInfo set LeftMoney = LeftMoney - @tranMoney where CardID = @cardId
            if(@@ERROR=0)
            begin
                commit transaction
                print 'OK'  
            end 
        end
        else
        begin
            rollback
            print 'error'
        end
    end
    else
            print '余額不足'
go
exec proc_getMoney '1324 3626 7532 1935',520
go
exec proc_getMoney '1027 3526 1536 1135',520
go
  1. 在存儲過程內創(chuàng)建事務,根據用戶輸入的個人信息,實現銀行卡開戶,輸出參數作為用戶的銀行卡卡號以及銀行卡余額(開戶時不僅要在用戶信息表和銀行卡表添加一條數據,也要在交易信息表中插入一條存款的記錄,因為開卡時需要指定開卡金額,銀行卡卡號自動生成)
if exists(select * from sysobjects where name = 'proc_openAccount')
drop procedure proc_openAccount
go
create proc proc_openAccount
    @CustName varchar(20),      --定義變量開戶人姓名
    @IDCard varchar(18),        --定義變量開戶人身份證號
    @TelePhone varchar(13),     --定義變量開戶人電話號碼
    @Address varchar(50),       --定義變量開戶人住址
    @openMoney money            --定義變量開戶存入現金金額
as
begin
begin transaction
    declare @CustID int,@CardID varchar(19)  --定義變量開戶人的賬戶編號,開戶的卡號
    exec proc_getCardNo  @CardID output --執(zhí)行自動生成卡號的存儲過程,將輸出值賦給變量@CardID
        --向賬戶表中插入數據
        insert into AccountInfo values
        (@CustName,@IDCard,@TelePhone,@Address)
    if(@@error != 0)--如果出錯
        rollback--事務回滾
    else
        begin
            set @CustID = @@identity     --獲取生成賬戶的編號CustID
            --向銀行卡表中插入數據
            insert into CardInfo values
            (@CardID,default,@CustID,'活期',getdate(),@openMoney,@openMoney,'否')
                if(@@error != 0)
                    rollback
                else
                    begin
                    --向交易表中插入數據
                    insert into TransInfo values
                    (@CardID,'存款',@openMoney,default)
                    if(@@error != 0)
                        begin
                            rollback
                            print '開戶失敗,插入數據錯誤!'
                        end
                    else
                        begin
                            print '開戶成功!'
                            print '卡號為:' + @CardID
                        end
                    end
        end
commit transaction
end
go
exec proc_openAccount '八戒','422322001550135015','027-8658888','高老莊',250
go

附:
實現生產銀行卡的存儲過程,該存儲過程能隨機的產生一個卡號輸出

if exists(select * from sysobjects where name = 'proc_getCardNo')
    drop procedure proc_getCardNo
    go
    create proc proc_getCardNo
        @CardNo varchar(19) output  --定義輸出參數的類型
    as
    begin
        declare @day varchar(2) --定義日期
        set @day = dateName(dd,getdate())
        if @day<10  --如果日期小于10,要對其加'0'
        set @day = '0'+@day
        set @CardNo = convert(varchar(9),(dateName(yyyy,getdate())+' '
+ dateName(mm,getdate())))+@day+' '+ convert(varchar(10),(dateName(hh,getdate())
+dateName(mi,getdate())+' '+ subString(convert(varchar(6),rand(datepart(ms,getdate()))*1000000),1,5)))  
    end
go
declare @card varchar(19)
exec proc_getCardNo  @card output
print '卡號為:' + @card
go

本文就介紹到這里。
如有疑問請聯系我。

本文采用知識共享署名-相同方式共享 4.0 國際許可協(xié)議進行許可。
基于簡書上的作品創(chuàng)作。 可轉載、引用,但需經本人同意后署名作者且注明文章出處,并以相同方式共享。

知識共享許可協(xié)議
知識共享許可協(xié)議

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容