.NETのOracle Databaseトランザクションの使用
Jason Price著
Visual Basic .NETおよびC#の基本的なデータベース・トランザクションのコーディングについて学習します。
関連するダウンロード・リンク
ここでは、Visual Basic .NET(VB.NET)およびVisual C# .NET(C#)のデータベース・トランザクションの使用方法を学習します。 とくに、データベース・トランザクションを確認し、.NETプログラムでOracleTransactionオブジェクトを使用して、トランザクションのセーブポイントの設定方法を検討します。 参照するすべてのスクリプトとファイルは、ここ から取得できます。 この記事では、一般的なC#およびVB.NETプログラミングに精通していることを前提としています。
必要なソフトウェア
この記事に示されている例を実行する前に、次のソフトウェアをインストールする必要があります。
Enterprise Servicesトランザクションまたは分散トランザクションを使用してアプリケーションを開発および実行する場合、Oracle Services for Microsoft Transaction Server(10.1.0.2.0以降)もインストールする必要があります。
.NET FrameworkとSDKを個別にダウンロードしてインストール(最初に.NET Frameworkをインストール)する必要があります。 また、Oracle Data Provider for .NET(ODP.NET)を含むOracle Database 10gもダウンロードおよびインストールする必要があります。 個別のマシンまたは同じマシンにODP.NETおよびデータベース・サーバーをインストールできます。
注:Oracleデータベースへアクセスする際に最大のパフォーマンスが実現するよう、ODP.NETドライバは設計されています。また、BFILE、BLOB、CLOB、XMLTypeなどのOracleデータベースの豊富な機能もサポートされます。 Oracleデータベースに対して実行する.NETアプリケーションを開発している場合、ODP.NETは、機能およびパフォーマンスの両面で最適なデータ・アクセス・ソリューションになります。
データベース・スキーマの設定
最初に、Webストアの簡潔な例としてデータベース・スキーマを設定する必要があります。 storeというユーザーを作成してから、次のように必要な権限を付与します(CREATE USER権限をもつユーザーとしてデータベースにログインして、ユーザーを作成します)。
CREATE USER store IDENTIFIED BY store;
GRANT connect, resource TO store;
注:db1.sqlソース・コード・ファイルでストア・スキーマを設定する上記の2つの文とこの項のほかの文を確認できます。
次の文でstoreユーザーとして接続します。
CONNECT store/store;
次の文では、product_typesおよびproductsという2つの必要なデータベース表を作成します。
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 文でほかの口座に加えます。 加算と減算の両方をデータベースに永続的に記録するか、または取り消す必要があります。そうしないと、その金額が行方不明になります。 この簡潔な例では2つの UPDATE 文だけを使用していますが、実際のトランザクションでは多くの文( INSERT、UPDATE 、 DELETE )で構成される場合があります。
トランザクションのSQL文の結果を永続的に記録するには、 COMMIT 文でコミットを実行します。 SQL文の結果を取り消すには、すべての行を元の状態に再設定する ROLLBACK 文でロールバックを実行します。 事前にデータベースの接続を解除していない限り、ロールバックの実行前におこなわれた変更は取り消されます。 トランザクションを特定の時点にロールバックするために使用されるセーブポイントも設定できます。この際、トランザクションのほかの文は変更しません。
C#およびVB.NETのデータベース・トランザクションの使用
OracleTransactionクラスのオブジェクトを使用して、トランザクションを表すことができます。 OracleTransactionクラスのプロパティには、トランザクションに関連づけるデータベース接続を指定するConnectionや、トランザクション分離レベルを指定するIsolationLevelがあります。
OracleTransactionクラスには、トランザクションを制御する多くのメソッドがあります。 Commit() メソッドを使用してSQL文を永続的にコミットし、Rollback()を使用してSQL文を取り消します。 また、 Save() を使用して、トランザクションのセーブポイントを設定できます。
C#のプログラム(TransExample1.cs)とVB.NETのプログラム(TransExample1.vb)の2つのサンプル・プログラムの手順を段階的に説明します。 これらのプログラムは、2つの INSERT 文を含むトランザクションの実行方法を示します。 最初の INSERT は、行をproduct_types表に追加します。2つ目のINSERTは、行をproducts表に追加します。
名前空間のインポート
次のC#プログラム文は、SystemおよびOracle.DataAcess.Client名前空間のプログラムでの使用を指定します。
using System;
using Oracle.DataAccess.Client;
同等のVB.NET文は、以下のとおりです。
Imports System
Imports Oracle.DataAccess.Client
ODP.NETの一部のOracle.DataAccess.Client名前空間には、OracleConnection、OracleCommand、OracleTransactionクラスなどが含まれます。 サンプル・プログラムでこれらのクラスが使用されます。
手順1
最初に、Oracleデータベースに接続するOracleConnectionオブジェクトを作成し、接続を開きます。
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();
VB.NET:
Dim myOracleTransaction As OracleTransaction = _
myOracleConnection.BeginTransaction()
手順3
3つ目の手順では、SQL文を格納するOracleCommandオブジェクトを作成します。
C#:
OracleCommand myOracleCommand = myOracleConnection.CreateCommand();
VB.NET:
Dim myOracleCommand As OracleCommand =
myOracleConnection.CreateCommand
OracleConnectionオブジェクトの CreateCommand() メソッドを使用してOracleCommandオブジェクトが作成されたので、手順2で設定されたOracleConnectionオブジェクトのトランザクションが自動的に使用されます。
手順4
4つ目の手順では、行をproduct_types表に追加する最初の INSERT 文をOracleCommandオブジェクトのCommandTextプロパティに設定します。
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
5つ目の手順では、OracleCommandオブジェクトの ExecuteNonQuery() メソッドを使用して、 INSERT 文を実行します。
C#:
myOracleCommand.ExecuteNonQuery();
VB.NET:
myOracleCommand.ExecuteNonQuery()
手順6および7
6つ目および7つ目の手順では、行をproducts表に追加して実行する2つ目の INSERT 文を、OracleCommandオブジェクトのCommandTextプロパティに設定します。
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
8つ目の手順では、OracleTransactionオブジェクトの Commit() メソッドを使用して、データベースのトランザクションをコミットします。
C#:
myOracleTransaction.Commit();
VB.NET:
myOracleTransaction.Commit()
Commit() メソッドの完了後、 INSERT 文で追加された2つの新しい行がデータベースに永続的に保存されます。
手順9
9つ目の手順では、 Close() メソッドを使用して、OracleConnectionオブジェクトを閉じます。
C#:
myOracleConnection.Close();
VB.NET:
myOracleConnection.Close()
サンプル・プログラムのコンパイルおよび実行
サンプルのC#プログラムをコンパイルするには、cscコマンドを使用してC# コンパイラを実行します。 プログラムでOracle Data Access DLLを使用しているので、DLLのフルパスを指定する/rオプションを使用します。以下に例を挙げます。
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 Databaseの.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をコンパイルおよび実行できます。
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個の製品を変更する場合があります。2回目の変更バッチで間違えた場合、セーブポイントにロールバックでき、最初の変更バッチは維持されます。
セーブポイントの使用方法を示すC#(TransExample2.cs)およびVB.NET(TransExample2.vb)のサンプル・プログラムで、関連する新しい手順を段階的に説明します。 これらのプログラムでは、products表への行の追加、セーブポイントの設定、products表への別の行の追加、セーブポイントへのロールバックの実行、およびproducts表の行の読取りを順番に実行します。 セーブポイントへロールバックしたあと、products表に追加された最初の行だけが残ります。 2つ目の行は削除されます。
手順1から3は、"C#およびVB.NETのデータベース・トランザクションの使用"の項の手順と同じなので、ここでは省略します。
手順4
4つ目の手順では、製品IDに6を使用して、行をproducts表に追加します。
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
5つ目の手順では、OracleTransactionオブジェクトのSave()メソッドを使用して、SaveProductというセーブポイントを設定します。
C#:
myOracleTransaction.Save("SaveProduct");
VB.NET:
myOracleTransaction.Save("SaveProduct")
手順6
6つ目の手順では、製品IDに7を使用して、別の行をproducts表に追加します。
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
7つ目の手順では、手順5で設定されたSaveProductセーブポイントへのロールバックを実行します。
C#:
myOracleTransaction.Rollback("SaveProduct");
VB.NET:
myOracleTransaction.Rollback("SaveProduct")
ロールバックの完了後、手順6で追加された2つ目の行が削除されますが、手順4で追加された最初の行は残ります。
TransExample2.csおよびTransExample2.vbの残りの手順では、products表の内容の表示、全体のトランザクションのロールバック、およびデータベースの接続の解除を実行します。
Oracle Services for Microsoft Transaction Serverの概要
Microsoft Transaction Serverは、インターネットまたはネットワーク・サーバーで実行される専用のトランザクション処理システムです。 Microsoft Transaction Serverは、クライアント・コンピュータに代わってアプリケーションおよびデータベース・トランザクション・リクエストをデプロイし管理します。
Microsoft Transaction Serverは、3層のサーバー中心アーキテクチャ・モデルのコンポーネントです。 このアプローチによって、アプリケーションの表示、ビジネス・ロジック、およびデータ要素がネットワークに接続された異なるコンピュータに明確に分離されます。 特別な統合を実行せずに、リリース8.0.6以降のOracle Databaseサーバーに接続するMicrosoft Transaction Serverのコンポーネントをデプロイできますが、最初に Oracle Services for Microsoft Transaction Server(US OTN、英語)をインストールする必要があります。
結論
この記事では、.NETプログラムのデータベース・トランザクションの使用例を確認しました。 OracleTransactionオブジェクトの作成、OracleTransactionオブジェクトを使用したデータベースへのトランザクションの送信、トランザクションを部分的にロールバックするセーブポイントの使用の手順を実施しました。
Jason Price 氏は、技術コンサルタント兼ライターです。マイクロソフト認定プロフェッショナルの資格を保有しており、ソフトウェア業界で10年以上の実績をもつ、Oracle認定DBAおよびアプリケーション開発者です。 また、『 Oracle Database 10g SQL』 (McGraw-Hill/Osborne、2004年)、『 Mastering C# Database Programming』 (Sybex、2004年)、『 Mastering Visual C# .NET Programming』 (Sybex、2003年)、『 Oracle9i JDBC Programming』 (McGraw-Hill/Osborne、2002年)、『 Java Programming with Oracle SQLJ 』(O'Reilly、2001年)の著者でもあります。