COM+ トランザクション
1. はじめに
COM+ にてオブジェクトを Transactional Object として構成した場合、同じトランザクションストリームに入るコンテキストの Happy/Doomed ビットをセットすることにより、そのトランザクション状態の管理を容易にします。
2. 概要
この資料のサンプルコードでは、TestMethod という名前のメソッド内部で、データベースへのレコードの追加を行います。明示的に BeginTrans, CommitTrans または RollbackTrans を呼び出すことにより、トランザクション処理を行うのではないことに注意してください。ここでは、GetObjectContext を用いてオブジェクトコンテキストのインターフェイスポインタを取得し、それを用いて SetAbort や SetComplete を呼び出します。これにより、この処理の成否をコンテキストにマークすることが出来ます。
3. 演習の流れ
尚、この演習では pubs データベースを利用します。環境をお持ちでない方は、5.補足 を参考にしてデータベースを準備してください。 また pubs という名前のシステム DSN も使用しますのでそれも作成してください。
4. 演習
4.1. コンポーネントの作成
1. コード (trans1.h, trans1.cpp) を準備します。
2. 以下の内容を makefile として保存します。trans1.h は以下の内容です。
#pragma once
trans1.cpp は以下の通り。タイプライブラリのインポート文は環境に合わせてパスを変更してください。また接続文字列では sa を使用しています。赤字の部分に sa のパスワードを設定します。
#define _ATL_APARTMENT_THREADED
#include <atlbase.h>
#include <atlcom.h>
[
object,
dual,
helpstring("ITest Interface"),
pointer_default(unique)
]
__interface ITest : IDispatch {
[id(1), helpstring("TestMethod")] HRESULT TestMethod ([in] BOOL bAbort);
};
[
coclass,
threading("apartment"),
vi_progid("MyTest.Trans1"),
progid("MyTest.Trans1.1"),
version(1.0),
helpstring("Trans1 class")
]
class ATL_NO_VTABLE CTest : public ITest {
public:
// Constructor and Destructor
CTest () {}
// Methods
STDMETHOD(TestMethod)(BOOL bAbort);
};#include "trans1.h"
#include <comsvcs.h>
#import "C:\\Program Files\\Common Files\\System\\ado\\msado26.tlb" no_namespace rename("EOF", "adoEOF")
[
module(dll, name = "Trans1COM",
helpstring = "Trans1 Type library")
]
class CTrans1COMModule { };
STDMETHODIMP CTest::TestMethod (BOOL bAbort) {
_ConnectionPtr pConn = NULL;
HRESULT hr = S_OK;
_bstr_t strCmd;
// Open a connection.
pConn.CreateInstance (__uuidof(Connection));
pConn->Open (
"DSN=pubs;uid=sa;pwd=password;", (BSTR) NULL, (BSTR) NULL, adConnectUnspecified);
// Command string.
strCmd = "INSERT INTO jobs (job_desc, min_lvl, max_lvl) VALUES ('Support', 100, 200)";
IObjectContext* pContext = NULL;
hr = GetObjectContext (&pContext);
if (FAILED(hr)) {
printf ("Failed to get an object context.\n");
goto closedb;
}
try {
pConn->Execute (strCmd, NULL, adOptionUnspecified);
if (bAbort) {
pContext->SetAbort ();
}
else {
pContext->SetComplete ();
}
printf ("OK.\n");
}
catch(_com_error &e) {
// Notify the user of errors if any.
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
printf ("Aborted\n");
printf("Source : %s\n",(LPCSTR)bstrSource);
printf("Description : %s\n",(LPCSTR)bstrDescription);
}
closedb:
if (pConn) {
if (adStateOpen == pConn->State) {
pConn->Close ();
}
}
return S_OK;
}
TARGETNAME=trans1
OUTDIR=.\chk
LINK32=link.exe
ALL : "$(OUTDIR)\$(TARGETNAME).dll"
reg:
regsvr32 $(OUTDIR)\$(TARGETNAME).dll
unreg:
regsvr32 /u $(OUTDIR)\$(TARGETNAME).dll
test:
cscript test.vbs
CPPFLAGS=\
/nologo\
/EHsc\
/W3\
/c\
/ZI\
/TP\
/Fo"$(OUTDIR)\\"\
/Fd"$(OUTDIR)\\"\
/DWIN32\
/D_ATL_ATTRIBUTES\
/D_ATL_STATIC_REGISTRY\
/DUNICODE\
/D_UNICODE
LINK32_FLAGS=\
kernel32.lib\
ole32.lib\
oleaut32.lib\
uuid.lib\
comsvcs.lib\
/OUT:$(OUTDIR)\$(TARGETNAME).dll\
/DLL\
/IDLOUT:"$(OUTDIR)\_$(TARGETNAME).idl"\
/DEBUG\
/PDB:"$(OUTDIR)\$(TARGETNAME).pdb"\
/SUBSYSTEM:WINDOWS\
/IMPLIB:"$(OUTDIR)\$(TARGETNAME).lib"\
/MACHINE:X86
LINK32_OBJS=$(OUTDIR)\$(TARGETNAME).obj
"$(OUTDIR)\$(TARGETNAME).dll" : "$(OUTDIR)" $(LINK32_OBJS)
$(LINK32) $(LINK32_FLAGS) $(LINK32_OBJS)
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
.c{$(OUTDIR)}.obj:
$(CPP) $(CPPFLAGS) $<
.cpp{$(OUTDIR)}.obj:
$(CPP) $(CPPFLAGS) $<
3. ビルドします。
> nmake
4.2 コンポーネントの登録
1. コンポーネントサービス スナップインを開きます。
2. COM+ アプリケーションを作成します。
名前: TransTest
Activation Type: ライブラリアプリケーション
3. TransTest\Components に手順 4.1 で作成した trans1.dll をドラッグアンドドロップします。
4. コンポーネントのプロパティを開き、[Transactions] タブからトランザクションのサポート (Transaction support) を Required に設定します。
4.3 クライアントの作成
1. コンポーネントを呼び出すクライアントは以下のスクリプトです。test1.vbs として保存してください。
Dim obj, bAbort
bAbort を 1 に設定したときは、trans1.cpp 中の pConn->Execute 呼出し後に SetAbort を呼び出すパスを通ります。一方、bAbort を 0 に設定すると、SetComplete を呼び出すパスを通ります。
Set obj = CreateObject("MyTest.Trans1")
bAbort = 1
obj.TestMethod (bAbort)
Set obj = Nothing
4.4 動作確認
1. コンポーネントサービススナップインから、Distributed Transaction Coordinator 以下の Transaction Statistics を開きます。
MEMO: 統計のカウンタをゼロにリセットするには、msdtc を再起動します。
2. 次のコマンドで test1.vbs を実行します。
> cscript test1.vbs
3. Aborted がカウントされていることを確認します。
4. jobs テーブルに何も追加されていないことを確認します。
osql を使用する場合は、以下のようにします。
> osql -E
1> use pubs
2> go
1> select * from jobs order by job_id
2> go
job_id job_desc min_lvl max_lvl
------ -------------------------------------------------- ------- -------
1 New Hire - Job not specified 10 10
2 Chief Executive Officer 200 250
...
13 Sales Representative 25 100
14 Designer 25 100
(14 rows affected)
5. test1.vbs の bAbort を 0 に変更して保存します。
6. もう一度 test1.vbs を実行します。
> cscript test1.vbs
7. 次は Committed カウントが増え、データが追加されたことを確認します。
>osql -E
1> use pubs
2> go
1> select * from jobs order by job_id
2> go
job_id job_desc min_lvl max_lvl
------ -------------------------------------------------- ------- -------
1 New Hire - Job not specified 10 10
...
13 Sales Representative 25 100
14 Designer 25 100
20 Support 100 200
(15 rows affected)
5. 補足: MSDE を用いた pubs データベース のセットアップ
5.1 MSDE のインストール
> setup SAPWD="<password>"
OS を再起動します。
5.2 サンプルデータベース pubs のセットアップ
instpubs.sql は VS.NET のサンプルに付属しています。
>osql -E -iinstpubs.sql
試しに pubs データベースにクエリーを実行します。結果が返れば OK です。
C:\>osql -E
1> use pubs
2> go
1> SELECT * FROM Authors
2> go
au_id au_lname au_fname phone address
state zip contract
----------- ---------------------------------------- --------------------
------------ ------------
172-32-1176 White Johnson 408 496-7223 10932 Bigge
...(省略)...
UT 84152 1
(23 rows affected)
1> INSERT INTO jobs (job_desc,
min_lvl, max_lvl) VALUES ('Support', 100, 200)
2> go
(1 row affected)
1> SELECT * FROM jobs ORDER BY job_id
2> go
job_id job_desc min_lvl max_lvl
------ -------------------------------------------------- ------- -------
1 New Hire - Job not specified 10 10
2 Chief Executive Officer 200 250
...
14 Designer 25 100
15 Support 100 200
(15 rows affected)
1> DELETE FROM jobs WHERE job_desc='Support'
2> go
(1 row affected)
1> SELECT * FROM jobs ORDER BY job_id
2> go
job_id job_desc min_lvl max_lvl
------ -------------------------------------------------- ------- -------
1 New Hire - Job not specified 10 10
2 Chief Executive Officer 200 250
...
13 Sales Representative 25 100
14 Designer 25 100
(14 rows affected)
1>
5.3 システム DSN の作成
1. 管理ツールの中から Data Sources (ODBC) を開きます。
2. [System DSN] タブを選択し、[Add] をクリックします。
3. SQL Server を選択して [Finish] をクリックします。
4. ウィザードには以下の図の通りに答えます。
DSN 名は pubs にします。
ここはそのまま [Next] をクリックします。
[Change the default database to] をチェックして pubs を選択します。
ここはデフォルトのまま [Finish] をクリックします。
[Test Data Source] をクリックし、接続テストを行います。
次の画面が表示されれば成功です。