在本文中,您將了解到如何在 Visual Basic .NET (VB.NET) 和 Visual C# .NET (C#) 中使用數據庫事務。具體來講,您將系統學習數據庫事務、在 .NET 程序中使用 OracleTransaction 對象以及如何設置事務保存點。本文中引用的所有腳本和文件都在這里提供。                                                                                            本文假定您大體上熟悉 C# 和 VB.NET 編程。  所需軟件  假如您要跟隨我們逐步完成本文中給出的示例,那么您需要安裝以下軟件:  Windows NT 4.0、windows 2000、Windows xp PRofessional 或 Windows Server 2003  能夠訪問一個已安裝的 Oracle 數據庫(Oracle8i 版本 3 8.1.7 或更高版本)  Oracle 客戶機(版本 10.1.0.2.0 或更高版本)  Oracle Net(版本 10.1.0.2.0 或更高版本)  Oracle Data Providers for .NET(版本 10.1.0.2.0 或更高版本)  Microsoft .NET Framework(版本 1.0 或更高版本)  Microsoft .NET 框架 SDK(版本 1.0 或更高版本)  假如您打算使用企業服務事務或分布式事務來開發和運行應用程序,那么您還需要安裝 Oracle Services for Microsoft Transaction Server(10.1.0.2.0 或更高版本)。  您需要分別下載和安裝 .NET 框架以及 SDK(先安裝框架)。您還需要下載和安裝 Oracle 數據庫 10g,它包括 Oracle Data Provider for .NET (ODP.NET)。您可以選擇在不同計算機或同一計算機上安裝 ODP.NET 和數據庫服務器。  注重:ODP.NET 驅動程序針對 Oracle 數據庫訪問進行了優化,因此可以獲得最佳性能,并且它們還支持 Oracle 數據庫的豐富特性,如 BFILE、BLOB、CLOB、xmlType 等。假如您正在開發基于 Oracle 數據庫的 .NET 應用程序,那么就特性和性能來講,ODP.NET 無疑是最佳的選擇。  數據庫模式設置  首先,您需要設置數據庫模式,在此我們使用一個簡化的 Web 商店示例。您必須首先創建一個名為 store 的用戶并按以下方式將所需的權限授予該用戶(您必須首先以擁有 CREATE USER 權限的用戶身份登錄數據庫才能創建用戶):  CREATE USER store IDENTIFIED BY store;
  GRANT connect, resource TO store;  注重:您會在源代碼文件 db1.sql 中找到前兩個語句和該部分中出現的設置 store 模式的其他語句。  接下的語句以 store 用戶身份進行連接:  CONNECT store/store;  以下語句創建了所需的兩個數據庫表,名稱分別為 prodUCt_types 和 products:  CREATE TABLE product_types (
  product_type_id INTEGER
  CONSTRAINT product_types_pk PRIMARY KEY,
  name VARCHAR2(10) NOT NULL
  );  CREATE TABLE products (
  product_id INTEGER
  CONSTRAINT products_pk PRIMARY KEY,
  product_type_id INTEGER
  CONSTRAINT products_fk_product_types
  REFERENCES product_types(product_type_id),
  name VARCHAR2(30) NOT NULL,
  description VARCHAR2(50),
  price NUMBER(5, 2)
  );
                           注重:假如您在一個不同的模式中為 store 用戶創建了這些數據庫表,那么您將需要修改示例配置文件(您稍后將看到)中的模式名稱。  表 product_types 用于存儲示例在線商店可能庫存的產品類型的名稱,表 products 包含了所銷售產品的具體信息。  下面的 INSERT 語句為表 product_types 和 products 添加行:  INSERT INTO product_types (
  product_type_id, name
  ) VALUES (
  1, 'Book'
  );
  INSERT INTO product_types (
  product_type_id, name
  ) VALUES (
  2, 'DVD'
  );  INSERT INTO products (
  product_id, product_type_id, name, description, price
  ) VALUES (
  1, 1, 'Modern Science', 'A description of modern science', 19.95
  );
  INSERT INTO products (
  product_id, product_type_id, name, description, price
  ) VALUES (
  2, 1, 'Chemistry', 'Introduction to Chemistry', 30.00
  );
  INSERT INTO products (
  product_id, product_type_id, name, description, price
  ) VALUES (
  3, 2, 'Supernova', 'A star explodes', 25.99
  );
  INSERT INTO products (
  product_id, product_type_id, name, description, price
  ) VALUES (
  4, 2, 'Tank War', 'Action movie about a future war', 13.95
  );  COMMIT;  接下來,您將了解有關數據庫事務的內容。  數據庫事務簡介  數據庫事務是由一組 SQL 語句組成的一個邏輯工作單元。您可以把事務看作是一組不可分的 SQL 語句,這些語句作為一個整體永久記錄在數據庫中或一并撤銷。比如在銀行帳戶之間轉移資金:一條 UPDATE 語句將從一個帳戶的資金總數中減去一部分,另一條 UPDATE 語句將把資金加到另一個帳戶中。減操作和加操作必須永久記錄在數據庫中,或者必須一并撤銷 ― 否則將損失資金。這個簡單的示例僅使用了兩條 UPDATE 語句,但一個更實際的事務可能包含許多 INSERT、UPDATE 和 DELETE 語句。  要永久記錄一個事務中的 SQL 語句的結果,您可以通過 COMMIT 語句來執行提交。要撤銷 SQL 語句的結果,您可以使用 ROLLBACK 語句來執行回滾,這會把所有的行重設為它們原來的狀態。只要您事先沒有與數據庫斷開,則您在執行回滾之前所做的任何修改都將被撤銷。您還可以設置一個保存點,以便將事務回滾至該特定的點,同時保持事務中的其他語句原封不動。  在 C# 和 VB.NET 中使用數據庫事務  您可以使用 OracleTransaction 類的一個對象來表示一個事務。OracleTransaction 類包含多個屬性,其中的兩個為 Connection(指定與事務關聯的數據庫連接)和 IsolationLevel(指定事務隔離級別);本文稍后將向您介紹更多有關事務隔離級別的內容。  OracleTransaction 類包含許多操控事務的方法。您可以使用 Commit() 方法永久提交 SQL 語句,并可以使用 Rollback() 撤銷這些語句。您還可以使用 Save() 在事務中設置一個保存點。  我現在將帶著您逐步完成兩個示例程序 ― 一個用 C# 編寫 (TransExample1.cs),另一個用 VB.NET 編寫 (TransExample1.vb)。這些程序演示了如何執行一個包含了兩條 INSERT 語句的事務。第一條 INSERT 語句將在表 product_types 中添加一行,第二條將在表 products 中添加一行。  導入命名空間  以下 C# 程序語句指定在程序中使用 System 和 Oracle.DataAcess.Client 命名空間:  using System;
  using Oracle.Dataaccess.Client;  下面是等價的 VB.NET 語句:  Imports System
  Imports Oracle.DataAccess.Client  Oracle.DataAccess.Client 命名空間是 ODP.NET 的一部分,它包含許多類,其中有 OracleConnection、OracleCommand 和 OracleTransaction。示例程序用到了這些類。  第 1 步  創建一個 OracleConnection 對象連接到 Oracle 數據庫,然后打開該連接。  在 C# 中:  OracleConnection myOracleConnection =
  new OracleConnection(
  "User Id=store;PassWord=store;Data Source=ORCL"
    );
  myOracleConnection.Open();
  在 VB.NET 中:
                           Dim myOracleConnection As New OracleConnection( _
  "User Id=store;Password=store;Data Source=ORCL")
  myOracleConnection.Open()  User Id 和 Password 屬性指定了您所要連接到的模式的數據庫用戶和口令。Data Source 屬性指定了數據庫的 Oracle Net 服務名稱;初始數據庫的默認服務名稱為 ORCL。假如您使用的不是初始數據庫,或者您的服務名稱不同,那么您需要在程序中修改 Data Source 屬性的設置。  第 2 步  創建一個 OracleTransaction 對象,然后調用 OracleConnection 對象的 BeginTransaction() 方法啟動事務。  在 C# 中:  OracleTransaction myOracleTransaction =
  myOracleConnection.BeginTransaction();
  In VB.NET:  Dim myOracleTransaction As OracleTransaction = _
  myOracleConnection.BeginTransaction()  第 3 步  創建一個 OracleCommand 對象,用于存儲 SQL 語句。  在 C# 中:  OracleCommand myOracleCommand = myOracleConnection.CreateCommand();  在 VB.NET 中:  Dim myOracleCommand As OracleCommand =
  myOracleConnection.CreateCommand  因為 OracleCommand 對象使用 OracleConnection 對象的 CreateCommand() 方法創建的,所以它自動使用在第 2 步中為 OracleConnection 對象設置的事務。  第 4 步  將 OracleCommand 對象的 CommandText 屬性設為向表 product_types 中添加一行的第一條 INSERT 語句。  在 C# 中:  myOracleCommand.CommandText =
  "INSERT INTO product_types (" +
  "  product_type_id, name" +
  ") VALUES (" +
  "  3, 'Magazine'" +
    ")";  在 VB.NET 中:  myOracleCommand.CommandText = _
  "INSERT INTO product_types (" & _
  "  product_type_id, name" & _
  ") VALUES (" & _
  "  3, 'Magazine'" & _
    ")"
  
  第 5 步  使用 OracleCommand 對象的 ExecuteNonQuery() 方法運行 INSERT 語句。  在 C# 中:  myOracleCommand.ExecuteNonQuery();  在 VB.NET 中:  myOracleCommand.ExecuteNonQuery()  第 6 和第 7 步  將 OracleCommand 對象的 CommandText 屬性設為向表 Products 中添加一行的第二條 INSERT 語句,并運行它。  在 C# 中:  myOracleCommand.CommandText =
  "INSERT INTO products (" +
  "  product_id, product_type_id, name, description, price" +
  ") VALUES (" +
  "  5, 3, 'Oracle Magazine', 'Magazine about Oracle', 4.99" +
    ")";
  myOracleCommand.ExecuteNonQuery();  在 VB.NET 中:  myOracleCommand.CommandText = _
  "INSERT INTO products (" & _
  "  product_id, product_type_id, name, description, price" & _
  ") VALUES (" & _
  "  5, 3, 'Oracle Magazine', 'Magazine about Oracle', 4.99" & _
    ")"
  myOracleCommand.ExecuteNonQuery()  第 8 步  使用 OracleTransaction 對象的 Commit() 方法提交數據庫中的事務。  在 C# 中:  myOracleTransaction.Commit();  在 VB.NET 中:  myOracleTransaction.Commit()  在完成 Commit() 方法之后,由 INSERT 語句添加的兩行將在數據庫中永久記錄。  第 9 步  使用 Close() 方法關閉 OracleConnection 對象。  在 C# 中:  myOracleConnection.Close();  在 VB.NET 中:  myOracleConnection.Close()
                           編譯并運行示例程序  要編譯 C# 示例程序,您可以使用 csc 命令運行 C# 編譯器。因為程序使用 Oracle Data Access DLL,所以您應使用 /r 選項指定該 DLL 的完整路徑,例如:  csc TransExample1.cs /r:C:/oracle/product/10.1.0/
  Client_1/bin/Oracle.DataAccess.dll  注重:您需要用您計算機上的相應路徑來替換該 DLL 的路徑。此外,假如您的計算機找不到 csc 編譯器,那么您可能需要運行 Microsoft sdkvars.bat 腳本來首先設置 .NET SDK 的環境變量;您可以在安裝 .NET SDK 的 bin 目錄中找到該腳本。  假如您碰到以下錯誤:  Example1.cs(10,7):error CS0246:The type or namespace name 'Oracle'
  could not be found (are you missing a using directive or an assembly reference?)  這說明您沒有在編譯命令中正確指定 Oracle Data Access DLL。(有關設置的信息,請參閱 John Paul Cook 的技術文章“在 Oracle 數據庫上構建 .NET 應用程序”。)  下面是用于編譯 VB.NET 程序的等價命令:  vbc TransExample1.vb /r:C:/oracle/product/10.1.0/
  Client_1/bin/Oracle.DataAccess.dll /r:system.dll /r:system.data.dll  接下來,輸入以下命令,運行示例:  TransExample1  您將看到程序的輸出。不過,假如您碰到類似以下的異常:  An exception was thrown
  Message = ORA-12514:TNS:listener does not currently know
  of service requested in connect descriptor  這說明 OracleConnection 對象的連接字符串中的 Data Source 的設置不正確。您應當咨詢您的 DBA 或查閱 Oracle Net 文檔以獲得更多具體信息。  假如您使用的是 VS .NET,那么您可以遵循以下指示來編譯和運行 C# 程序 TransExample1.cs:  創建一個新的 C# 控制臺應用程序。File>New Project,然后選擇 Visual C# Projects,Console application。  將項目命名為 TransExample1。  用 TransExample1.cs 中的代碼替換 VS .NET 生成的所有代碼。  選擇 Project>Add Reference 添加對 Oracle.DataAccess.dll 的引用,然后瀏覽至您安裝 ODP.NET 的目錄(在我的計算機上,它是 C:/oracle/product/10.1.0/Client_1/bin/Oracle.DataAccess.dll),然后雙擊 Oracle.DataAccess.dll。  選擇 Debug>Start without Debugging 運行該程序。  要編譯和運行 TransExample1.vb,您可以執行類似的一系列步驟,但第 1 步應選擇一個 Visual Basic 控制臺應用程序,并在第 3 步用 TransExample1.vb 中的代碼替換生成的代碼。  查看程序的運行結果  當您運行完 C# 或 VB .NET 程序時,您可以在 SQL*Plus 中使用以下 SELECT 語句查看事務的結果:  SELECT p.product_id, p.product_type_id, pt. name, p.name, p.description, p.price
  FROM products p, product_types pt
  WHERE p.product_type_id = pt.product_type_id
  AND p.product_id = 5;  您將看到以下結果:  PRODUCT_ID PRODUCT_TYPE_ID NAME       NAME
  ---------- --------------- ---------- -----------------------
  DESCRIPTION                                             PRICE
  -------------------------------------------------- ----------
  5               3 Magazine   Oracle Magazine
  Magazine about Oracle                                    4.99
                           接下來,您將了解如何設置事務保存點。  在 .NET 程序中設置事務保存點  正如本文前面所提到的那樣,您可以設置一個保存點,以便將事務回滾至該特定的點,同時保持事務中的其他語句原封不動。您可以使用 OracleTransaction 類的 Save() 方法在事務中設置保存點。  假如您有一個非常長的事務并且希望能夠僅回滾到某個特定的時間點,那么您可能要使用保存點。例如,您可能想對 10 個產品做一些更改,然后設置一個保存點,然后再對另 10 個產品做更改;假如您在進行第二批更改時出現了錯誤,那么您可以回滾至保存點,使您的第一批更改原封不動。  我將帶您逐步完成演示如何使用保存點的 C# (TransExample2.cs) 示例程序和 VB.NET (TransExample2.vb) 示例程序中的相關新步驟。這些程序向表 products 中添加一行,設置一個保存點,向表 products 中添加另一行,回滾至保存點,然后從表 products 中讀取這些行。在回滾至保存點后,只有添加到表 products 中的第一行保留了下來:第二行將已被刪除。  第 1 到第 3 步與“在 C# 和 VB.NET 中使用數據庫事務”部分中所示的步驟相同,因此在這里將其省略。  第 4 步  向表 products 中添加一行,該行的產品 ID 為 6。  在 C# 中:    myOracleCommand.CommandText =
  "INSERT INTO products (" +
  "  product_id, product_type_id, name, description, price" +
  ") VALUES (" +
  "  6, 2, 'Man from Another World', 'Man from Venus lands on Earth', 24.99" +
    ")";
  myOracleCommand.ExecuteNonQuery();  在 VB.NET 中:  myOracleCommand.CommandText = _
  "INSERT INTO products (" & _
  "  product_id, product_type_id, name, description, price" & _
    ") VALUES (" & _
  "  6, 2, 'Man from Another World', 'Man from Venus lands on Earth', 24.99" & _
    ")"
  myOracleCommand.ExecuteNonQuery()  第 5 步  使用 OracleTransaction 的 Save() 方法設置一個名為 SaveProduct 的保存點。  在 C# 中:  myOracleTransaction.Save("SaveProduct");  在 VB.NET 中:  myOracleTransaction.Save("SaveProduct")  第 6 步  向表 products 中添加另一行,該行的產品 ID 為 7。  在 C# 中:  myOracleCommand.CommandText =
  "INSERT INTO products (" +
  "  product_id, product_type_id, name, description, price" +
  ") VALUES (" +
  "  7, 2, 'Z-Files', 'Mysterious stories', 14.99" +
    ")";
  myOracleCommand.ExecuteNonQuery();  在 VB.NET 中:  myOracleCommand.CommandText = _
  "INSERT INTO products (" & _
  "  product_id, product_type_id, name, description, price" & _
  ") VALUES (" & _
  "  7, 2, 'Z-Files', 'Mysterious stories', 14.99" & _
    ")"
  myOracleCommand.ExecuteNonQuery()  第 7 步  回滾到先前在第 5 步中設置的 SaveProduct 保存點。  在 C# 中:  myOracleTransaction.Rollback("SaveProduct");  在 VB.NET 中:  myOracleTransaction.Rollback("SaveProduct")  完成回滾后,在第 6 步中添加的第二行已被刪除,而在第 4 步中添加的第一行保留了下來。  TransExample2.cs 和 TransExample2.vb 中剩下的步驟顯示表 products 的內容,回滾整個事務并從數據庫斷開。  用于 Microsoft Transaction Server 的 Oracle 事務服務的快速說明  Microsoft Transaction Server 是一個運行在互聯網或網絡服務器上的專有事務處理系統。Microsoft Transaction Server 為客戶端計算機部署和治理應用程序和數據庫事務請求。  Microsoft Transaction Server 是以服務器為中心的三層體系結構模型的一個組件。這種方法實現了將應用程序的表示、業務邏輯和數據元素清楚地分布到在一個網絡中連接的不同計算機上。無需專門集成,您就可以在與 Oracle 數據庫服務器 8.0.6 版或更高版本連接的 Microsoft Transaction Server 中部署一個組件,但首先您必須安裝 Oracle Services for Microsoft Transaction Server。
                           結論  在本文中,您系統學習了在 .NET 程序中使用數據庫事務。您了解了如何創建 OracleTransaction 對象并用它們將事務提交給數據庫,如何使用保存點部分回滾一個事務,以及 Oracle 數據庫如何分離并發事務。