事務回滾
事務的四個特性之一是原子性,其含義是指對於特定操作序列組成的事務,要麼全部完成,要麼就一件也不做。如果在事務處理的過程中,發生未知的不可預料的錯誤,如何保證事務的原子性呢?當事務中止時,必須執行回滾操作,以便消除已經執行的操作對數據庫的影響。
一般的情況下,在異常處理中使用回滾動作是比較好的想法。前面,我們已經得到了一個更新數據庫的程序,並且驗證了它的正確性,稍微修改一下,可以得到:
//RollBack.cs
using System;
using System.Data;
using System.Data.SqlClIEnt;
namespace ASPcn
{
public class DbTran
{
file://執行事務處理
public void DoTran()
{
file://建立連接並打開
SqlConnection myConn=GetConn();
myConn.Open();
SqlCommand myComm=new SqlCommand();
SqlTransaction myTran;
file://創建一個事務
myTran=myConn.BeginTransaction();
file://從此開始,基於該連接的數據操作都被認為是事務的一部分
file://下面綁定連接和事務對象
myComm.Connection=myConn;
myComm.Transaction=myTran;
try
{
file://定位到pubs數據庫
myComm.CommandText="USE pubs";
myComm.ExecuteNonQuery();
myComm.CommandText="UPDATE roysched SET royalty = royalty * 1.10 WHERE title_id LIKE 'Pc%'";
myComm.ExecuteNonQuery();
file://下面使用創建數據庫的語句制造一個錯誤
myComm.CommandText="Create database testdb";
myComm.ExecuteNonQuery();
myComm.CommandText="UPDATE roysched SET royalty = royalty * 1.20 WHERE title_id LIKE 'Ps%'";
myComm.ExecuteNonQuery();
file://提交事務
myTran.Commit();
}
catch(Exception err)
{
myTran.Rollback();
Console.Write("事務操作出錯,已回滾。系統信息:"+err.Message);
}
}
file://獲取數據連接
private SqlConnection GetConn()
{
string strSql="Data Source=localhost;Integrated Security=SSPI;user id=sa;passWord=";
SqlConnection myConn=new SqlConnection(strSql);
return myConn;
}
}
public class Test
{
public static void Main()
{
DbTran tranTest=new DbTran();
tranTest.DoTran();
Console.WriteLine("事務處理已經成功完成。");
Console.ReadLine();
}
}
}
首先,我們在中間人為地制造了一個錯誤——使用前面講過的Create database語句。然後,在異常處理的catch塊中有如下語句:
myTran.Rollback();
當異常發生時,程序執行流跳轉到catch塊中,首先執行的就是這條語句,它將當前事務回滾。在這段程序可以看出,在Create database之前,已經有了一個更新數據庫的操作——將pubs數據庫的roysched表中的所有title_id字段以“PC”開頭的書籍的royalty字段的值都增加0.1倍。但是,由於異常發生而導致的回滾使得對於數據庫來說什麼都沒有發生。由此可見,Rollback()方法維護了數據庫的一致性及事務的原子性。