C#資料庫事務原理及實踐(4)

來源:互聯網
上載者:User
使用儲存點
事務只是一種最壞情況下的保障措施,事實上,平時系統的運行可靠性都是相當高的,錯誤很少發生,因 此,在每次事務執行之前都檢查其有效性顯得代價太高——絕大多數的情況下這種耗時的檢查是不必要的。我們不得不想另外一種辦法來提高效率。
事 務儲存點提供了一種機制,用於復原部分事務。因此,我們可以不必在更新之前檢查更新的有效性,而是預設一個儲存點,在更新之後,如果沒有出現錯誤,就繼續 執行,否則復原到更新之前的儲存點。儲存點的作用就在於此。要注意的是,更新和復原代價很大,只有在遇到錯誤的可能性很小,而且預先檢查更新的有效性的代 價相對很高的情況下,使用儲存點才會非常有效。
使用.net架構編程時,你可以非常簡單地定義事務儲存點和復原到特定的儲存點。下面的語句定義了 一個儲存點“NoUpdate”:
myTran.Save("NoUpdate");
當你在程式中建立同名的儲存點時,新建立的儲存點將 替代原有的儲存點。
在復原事務時,只需使用Rollback()方法的一個重載函數即可:
myTran.Rollback("NoUpdate");
下 面這段程式說明了復原到儲存點的方法和時機:
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
  {
myComm.CommandText="use pubs";
myComm.ExecuteNonQuery();
myTran.Save("NoUpdate");
myComm.CommandText="UPDATE roysched SET royalty = royalty * 1.10 WHERE title_id LIKE 'Pc%'";
myComm.ExecuteNonQuery();
file:// 提交事務
myTran.Commit();
  }
  catch(Exception err)
  {
file:// 更新錯誤,復原到指定儲存點
myTran.Rollback("NoUpdate");
throw new ApplicationException("事務操作出錯,系統資訊:"+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();
}
  }
}

很 明顯,在這個程式中,更新無效的幾率是非常小的,而且在更新前驗證其有效性的代價相當高,因此我們無須在更新之前驗證其有效性,而是結合事務的儲存點機 制,提供了資料完整性的保證。

隔離等級的概念
企業級的資料庫每一秒鐘都可能應付成千上萬的並發訪問,因而帶來了並發 控制的問題。由資料庫理論可知,由於並發訪問,在不可預料的時刻可能引發如下幾個可以預料的問題:
髒讀:包含未提交資料的讀取。例 如,事務1 更改了某行。事務2 在事務1 提交更改之前讀取已更改的行。如果事務1 復原更改,則事務2 便讀取了邏輯上從未存在過的行。
不 可重複讀取:當某個事務不止一次讀取同一行,並且一個單獨的事務在兩次(或多次)讀取之間修改該行時,因為在同一個事務內的多次讀取之間修改了該 行,所以每次讀取都產生不同值,從而引發不一致問題。
幻象:通過一個任務,在以前由另一個尚未提交其事務的任務讀取的行的範圍中插 入新行或刪除現有行。帶有未提交事務的任務由於該範圍中行數的更改而無法重複其原始讀取。
如 你所想,這些情況發生的根本原因都是因為在並發訪問的時候,沒有一個機制避免交叉存取所造成的。而隔離等級的設定,正是為了避免這些情況的發生。事務準備 接受不一致資料的層級稱為隔離等級。隔離等級是一個事務必須與其它事務進行隔離的程度。較低的隔離等級可以增加並發,但代價是降低資料的正確性。相反,較 高的隔離等級可以確保資料的正確性,但可能對並發產生負面影響。
根據隔離等級的不同,DBMS為並行訪問提供不同的互斥保證。在SQL Server數 據庫中,提供四種隔離等級:未提交讀、提交讀、可重複讀、可串列讀。這四種隔離等級可以不同程度地保證並發的資料完整性:

隔離等級 髒 讀 不可重複讀取 幻 像
未提交讀
提 交讀
可重複讀
可 串列讀

可以看出,“可串列 讀”提供了最進階別的隔離,這時並發事務的執行結果將與串列執行的完全一致。如前所述,最進階別的隔離也就意味著最低程度的並 發,因此,在此隔離等級下,資料庫的服務效率事實上是比較低的。儘管可串列性對於事務確保資料庫中的資料在所有時間內的正確性相當重要,然而許多事務並不 總是要求完全的隔離。例如,多個作者工作於同一本書的不同章節。新章節可以在任意時候提交到項目中。但是,對於已經編輯過的章節,沒有編輯人員的批准,作 者不能對此章節進行任何更改。這樣,儘管有未編輯的新章節,但編輯人員仍可以確保在任意時間該書籍項目的正確性。編輯人員可以查看以前編輯的章節以及最近 提交的章節。這樣,其它的幾種隔離等級也有其存在的意義。
在.net架構中,事務的隔離等級是由枚舉 System.Data.IsolationLevel所定義的: 

[Flags]
[Serializable]
public enum IsolationLevel

其成員及相應的含義如下:

成 員 含 義
Chaos 無 法改寫隔離等級更高的事務中的暫止的變更。
ReadCommitted 在正在讀取資料時保持共用 鎖,以避免髒讀,但是在事務結束之前可以更改資料,從而導致不可重複的讀取或幻像資料。
ReadUncommitted 可 以進行髒讀,意思是說,不發布共用鎖定,也不接受獨佔鎖。
RepeatableRead 在查詢中使 用的所有資料上放置鎖,以防止其他使用者更新這些資料。防止不可重複的讀取,但是仍可以有幻像行。
Serializable 在 DataSet上放置範圍鎖,以防止在事務完成之前由其他使用者更新行或向資料集中插入行。
Unspecified 正 在使用與指定隔離等級不同的隔離等級,但是無法確定該層級。

顯而意見,資料庫的四個隔離級 別在這裡都有映射。
預設的情況下,SQL Server使用ReadCommitted(提交讀)隔離等級。
關於隔離等級的最後一點就是 如果你在事務執行的過程中改變了隔離等級,那麼後面的命名都在最新的隔離等級下執行——隔離等級的改變是立即生效的。有了這一點,你可以在你的事務中更靈 活地使用隔離等級從而達到更高的效率和並發安全性。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.