作者:Jason Price
原文地址:http://www.oracle.com/technology/global/cn/pub/articles/price_dbtrans_dotnet.html
瞭解在 Visual Basic .NET 和 C# 編寫資料庫事務的基礎知識。
範例程式碼:http://www.oracle.com/technology/pub/files/price_dbtrans_src.zip
在本文中,您將瞭解到如何在 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 中添加一行,該行的產品識別碼 為 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 中添加另一行,該行的產品識別碼 為 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 資料庫如何分離並發事務。
--------------------------------------------------------------------------------
技術顧問兼作家 Jason Price 是 Microsoft 認證專家、Oracle 認證資料庫管理員和應用程式開發人員,具有十多年的軟體行業從業經驗。他撰寫了《Oracle 資料庫 10g SQL》(McGraw-Hill/Osborne,2004)、《精通 C# 資料庫編程》(Sybex,2004)、《精通 Visual C# .NET 編程》(Sybex,2003)、《Oracle9i JDBC 編程》(McGraw-Hill/Osborne,2002)和《使用 Oracle SQLJ 進行 Java 編程》(O'Reilly,2001)。