C++ バインディングの使用法
この章では、Caché Perl バインディングを使用する C++ コードの具体例を紹介します。ここで説明する内容は以下のとおりです。
-
C++ バインディングの基礎 — Caché データベース・オブジェクトへのアクセスと操作に関する基本事項です。
-
プロキシ・オブジェクトの使用法 — プロキシ・オブジェクトへの参照であるオブジェクトを操作します。
-
コレクションの使用法 — Caché のリストと配列を反復処理します。
-
リレーションシップの使用法 — 埋め込みオブジェクトを操作します。
-
ストリームの使用法 — 長い文字列またはバイナリ・データを保持するプロパティを使用します。
-
クエリの使用法 — Caché クエリとダイナミック SQL クエリを実行します。
-
トランザクションの使用法 — トランザクションをコミットまたはロールバック・メソッドで制御します。
ここで紹介する例の多くは、サンプル・プログラムを変更したものです。コードを簡略化するため、引数処理とエラー・トラップ文 (try/catch) は除外されています。完全なサンプル・プログラムをロードして実行する方法の詳細は、"サンプル・プログラム" を参照してください。
C++ バインディングの基礎
Caché C++ バインディング・アプリケーションは非常にシンプルです。以下は、完全なサンプル・プログラムです。
#include "Sample_Person.h"
#include "Sample_Address.h"
int main()
{
// Connect to the Cache' database
d_connection conn = tcp_conn::connect("localhost[1972]:Samples",
"_system", "SYS");
Database db(conn);
// Create and use a Cache' object
d_ref<Sample_Person> person = Sample_Person::create_new(&db);
person->setName("Doe, Joe A");
person->setSSN("123-45-6789");
person->save();
// Print the result
std::cout << "w p.Name\n"
<< person->getName() << '\n';
return 0;
}
このコードはサンプル・ヘッダ・ファイルをインポートして、以下の処理を実行します。
-
Caché データベースの Samples ネームスペースに接続します。
-
Caché データベースへの接続に必要な情報を定義します。
-
d_connection オブジェクト (conn) を作成します。
-
d_connection オブジェクトを使用して、Database オブジェクト (database) を作成します。
-
-
Caché オブジェクトを作成し、使用します。
-
Database オブジェクトを使用して、Caché Sample.PersonOpens in a new tab クラスのインスタンスを作成します。
-
Sample.PersonOpens in a new tab オブジェクトの Name プロパティを設定します。
-
Name プロパティを取得し、出力します。
-
以下のセクションでは、これらの基本処理について詳しく説明します。
Caché データベースへの接続
Caché データベースへの物理的な接続を確立するには、d_connection クラスのインスタンスを生成します。d_connection はプロキシ・クラスであり、Conn_t (接続) クラス・インスタンスへのスマート・ポインタとして動作します。これは、参照する Conn_t オブジェクトの最後の参照が範囲外となったときに、自動的に Conn_t::disconnect() を呼び出します。つまり、ユーザは Conn_t::disconnect() を直接呼び出す必要はなく、Database オブジェクトは、誤って切断されることのない有効な接続を必ず保持していることを意味します。Conn_t は、これらのすべての接続に対し、共通のインタフェースを提供します。
d_connection オブジェクトで Database オブジェクトを初期化するには、d_connection オブジェクトが参照する Conn_t オブジェクトが接続されていて、他の Database インスタンスによって使用されていない必要があります。d_connection オブジェクトがこれらの要件を満たしているかどうかをテストするには、is_connected() 関数および is_busy() 関数を使用します。例えば、conn という名前の d_connection オブジェクトをテストする場合は、以下を実行します。
if (!conn->is_connected())
// code that makes conn point to an active connection
アクティブな接続を指していない d_connection オブジェクトは役に立たないため、そのコンストラクタはプライベートに設定されます。d_connection オブジェクトを生成するには、アクティブな接続を指す d_connection オブジェクトを返す Conn_t::connect() を呼び出す以外に方法はありません。接続が確立できない場合、d_connection オブジェクトはアクティブでない接続を参照します。
TCP/IP 接続クラスは、tcp_conn です。そのスタティック connect() メソッドは、以下の引数を取ります。
-
“host[port]:namespace” 形式の接続文字列
-
ユーザ名
-
パスワード
-
タイムアウト値
-
エラー値 — 接続に失敗した場合にエラー情報が含まれる、Db_err のオプションのアドレスです。
例えば以下のように記述します。
Db_err conn_err;
d_connection conn = tcp_conn::connect("localhost[1972]:Samples",
"_SYSTEM", "SYS", 0, &conn_err);
if (conn_err) {
// error handling
std::cerr << conn_err << '\n';
return -1;
}
try {
// establish the logical connection to Cache'
Database db(conn);
// code to use db here
}
catch(const Db_err& err) {
// handle an error from the C++ binding library
std::cout << err << std::endl;
}
C++ バインディング・アプリケーションのサンプル
このセクションでは、Caché C++ バインディングの使用例として、単純な C++ アプリケーションについて説明します。
サンプル・プログラムは Caché SAMPLES データベースに接続し、そのデータベース内に保存されている Sample.PersonOpens in a new tab オブジェクトのインスタンスを開いて変更し、それをデータベースに再度保存します。
#include "../Sample_Person.h"
#include "../Sample_Address.h"
typedef d_ref<Sample_Person> d_Sample_Person;
int main()
{
// establish the physical connection to Cache'
Db_err conn_err;
d_connection conn = tcp_conn::connect("localhost[1972]:Samples",
"_SYSTEM", "SYS", 0, &conn_err);
if (conn_err)
{
std::cerr << conn_err << '\n';
return -1;
}
try {
// establish the logical connection to Cache'
Database db(conn);
std::wstring id;
std::cout << "Enter ID of Person object to be opened:\n";
std::wcin >> id;
// open a Sample.Person object using %OpenId
d_Sample_Person person = Sample_Person::openid(&db, id.c_str());
// Fetch some properties of this object
std::cout << "Name " << person->getName() << '\n'
~<< "City " << person->getHome()->getCity() << '\n'
~<< '\n';
// Modify some properties
person->getHome()->setCity("Ulan Bator");
// Save the object to the database
person->save();
// Report the new residence of this person
std::cout << "New City: " << person->getHome()->getCity() << '\n';
return 0;
}
catch(const Db_err& err) {
std::cerr << err << '\n';
return -1;
}
// all objects are closed automatically
}
プロキシ・オブジェクトの使用法
オブジェクト値のプロキシ・タイプは、d_ref< > テンプレート・クラス (または Light C++ バインディング・クラスの lc_d_ref< > クラス) を使用して表されます。このテンプレートは、そのパラメータに、対応する C++ クラス名を取ります。例えば、Company オブジェクトへの参照は、d_ref<Company> として表されます。
d_ref<T> のインスタンスは、参照タイプ T のプロキシ・オブジェクトへのスマート・ポインタです。つまり、以下を実行できます。
-
"->" (ポインタ) 演算子を使用して、プロキシ・オブジェクトのメソッドを呼び出します。
-
1 つの d_ref< > をコピーします。この 2 つの d_ref< > インスタンスは、同じプロキシ・オブジェクトを指します。
-
プロキシ・メソッドに、引数として d_ref< > を渡すと、d_ref< > は別のプロキシ・オブジェクトを指します。
同じサーバ・オブジェクトを表す 2 つの変数が、2 つの異なるプロキシ・オブジェクトを指す場合もあります。
このライブラリは、開いているサーバ・オブジェクトごとにプロキシ・オブジェクトを 1 つのみ使用しようとしますが、ユーザが異なるプロキシ・クラスを使用してサーバ・オブジェクトを開いている場合は、同じサーバ・オブジェクトに異なるプロキシ・オブジェクトを使用する必要があります。"==" (等式テスト) および "!=" (非等式テスト) を使用して、d_ref<P> と d_ref<Q> が同じサーバ・オブジェクトを指しているかどうかをテストできます。
d_ref<T> は T へのポインタのように振る舞いますが、実際のポインタではありません。したがって、Null をテストしたり、d_ref<T> が Null を指すようにするには、メソッド呼び出し is_null() と make_null() を介して実行する必要があります。以下はその例です。
d_ref<Sample_Person> p1 = Sample_Person::openid(&db, L"1");
if (p1.is_null())
std::cerr << "the object is null";
p1.make_null();
これらのメソッドは、データ型クラスにも使用されます。
プロキシ・オブジェクトのキャスト
P が Q のサブクラスで、コンパイル時にタイプ確認が実行される場合、d_ref<P> を d_ref<Q> にキャストすることができます。以下はその例です。
d_ref<Sample_Employee> e1 = Sample_Employee::openid(&db, L"1");
d_ref<Sample_Person> p1 = e1; // ok
d_ref<Sample_Employee> e2 = p1; // gives a compile time error
Q が実際に P のサブクラスであることがわかっている場合、d_ref<Q> を d_ref<P> にキャストすることも可能ですが、NULL に関連するインタフェースと同様、関数呼び出し dynamic_cast() ではなく、conv_to() を介して実行する必要があります。これは、P と Q の間が、"isa" リレーションシップであるためです。conv_to は、参照によって渡された引数として結果を含む d_ref< > を取得し、変換が不可能な場合は、これを NULL に設定します。以下はその例です。
d_ref<Sample_Employee> e1 = Sample_Employee::openid(&db, L"1");
d_ref<Sample_Person> p2 = e1;
d_ref<Sample_Employee> e2; p2.conv_to(e2);
リソースの管理
d_ref< > は、自身が指すプロキシ・オブジェクトに関連するすべてのシステム・リソースを、自動的に管理します。以下はその例です。
d_ref<Sample_Person> p1 = Sample_Person::openid(&db, L"1");
p1->setDOB(1970,2,1);
d_ref<Sample_Person> p2 = p1->getSpouse();
change_to_spouse(p2); // p2 points to the same server object as p1
1 行目の openid() は、Sample_Person のスタティック・メソッドで、d_ref<Sample_Person> のインスタンスを生成します。2 行目では、インスタンスを使用して Person オブジェクトの誕生日を変更します。3 行目では、p2 がその人の配偶者を指すように設定し、4 行目では p2 が p1 と同じ人を指すように変更します。p1 および p2 によって取得されたすべてのリソースは、p1 および p2 が範囲外となったときに、自動的に開放されます。
コレクションの使用法
コレクションのプロキシは、C++ 標準ライブラリのフレームワークに適合するように設計されています。%ListOfObjectsOpens in a new tab および %ListOfDataTypesOpens in a new tab のプロキシは、std::vector のインタフェースとほぼ同じインタフェースを提供します。同様に、%ArrayOfObjectsOpens in a new tab および %ArrayOfDataTypesOpens in a new tab のプロキシは、std::map のインタフェースとほぼ同じインタフェースを提供します。
オブジェクトのコレクション
タイプ T のオブジェクトのコレクションに対するプロキシは、タイプ d_obj_coln_type<T> のオブジェクトを含みます。これらは、d_ref<T> として操作することもできますが、それらが指すオブジェクトの変更がサーバ上のコレクションに対してもすべて確実に反映される点で d_ref<T> とは異なります。特定のコレクションと指定されたキーに対するオブジェクトの値を変更するには、異なる d_ref<T> をオブジェクトに割り当てるだけで十分です。これらのオブジェクトは、コレクションでオブジェクトを開くことに伴う負荷を軽減するために、クライアント側で必要となるまでサーバ上のオブジェクトを開きません。
基本データ型のコレクション
データ型 T のコレクションのプロキシは、タイプ d_prim_coln_type<T> のオブジェクトを含みますが、これは T として操作できます。これらは、オブジェクトのコレクションに含まれるオブジェクトに類似していますが、オーバーヘッドはわずかなので直ちに初期化されます。
インタフェース
タイプ T の要素を持つ %ListOfObjectsOpens in a new tab は、タイプ d_obj_coln_type<T> の要素を持つ d_obj_vector<T> として生成され、d_ref<T> として操作できます。タイプ T の要素を持つ %ArrayOfObjectsOpens in a new tab は、タイプ d_obj_coln_type<T> の要素も持つ d_obj_map<T> として生成されます。
タイプ T の要素を持つ %ListOfDataTypesOpens in a new tab は、タイプ d_prim_coln_type<T> の要素を持つ d_prim_vector<T> として生成され、T として操作できます。タイプ T の要素を持つ %ArrayOfDataTypesOpens in a new tab は、タイプ d_prim_coln_type<T> の要素も持つ d_prim_map<T> として生成されます。
他のオブジェクトと同様に、コレクションは d_ref<T> 経由で操作する必要があります。つまり、スタティック・メソッド create_new() と openref() を呼び出すことにより、インスタンスを生成することができます。これらのメソッドは、シリアル・オブジェクトに対するプロキシの初期化に使用します。
d_obj_coln_type<T> と d_prim_coln_type<T> は、T から構築できます。つまり、d_obj_coln_type<T> または d_prim_coln_type<T> をとるすべての関数は、その引数が定数であれば、T によって呼び出すこともできます。
例
以下は、単純なコレクションの使用例です。
CPP.Coln クラスがプロパティ Lst を持つと、以下により C++ バインディング内でそのプロパティにアクセスすることができます。Lst は %ListOfObjectsOpens in a new tab で、1 つ以上の Sample.PersonOpens in a new tab のインスタンスを保持します。
d_ref< d_obj_vector<Sample_Person> > list = obj->getLst();
obj は、タイプ d_ref<CPP_Coln> のオブジェクトです。
コレクション内で list が指す 3 番目の Sample.PersonOpens in a new tab には、以下によりアクセスできます。
(*list)[2]
または
*(list->begin()+2)
person の名前には、以下によりアクセスできます。
(*list)[2]->getName()
または
(*(list->begin()+2))->getName()
list が d_ref<T> なので、"." の代わりに "->" を使用します。これは、実際のオブジェクトへのポインタのように動作します。
(d_ref<Sample.Person> 型の) p は、list が指すコレクションに以下のように挿入できます。
list->push_back(p);
コレクション内で list が指す 2 番目の Sample.PersonOpens in a new tab は、以下により消去できます。
list->erase(list->begin()+1);
コレクション内で list が指すすべての person は、以下により印刷できます。
class Print_person : public std::unary_function<d_ref<Sample_Person>, int> {
private:
std::ostream& out;
public:
explicit Print_person(std::ostream& o)
: out(o)
{};
result_type operator()(const argument_type& p) const;
{ out << p->getName() << std::endl; return 0; };
};
void print_people(d_ref<CPP_Coln>& obj)
{
d_ref< d_obj_vector<Sample_Person> > list = obj->getLst();
std::for_each(list->begin(), list->end(), Print_person(std::cout));
};
メソッドでのコレクション要素の使用法
通常、コレクション・プロキシの実際のタイプが (T または d_ref<T>ではなく) d_prim_coln_type<T> または d_obj_coln_type<T> であることに注意を払う必要はありません。しかし、これらのタイプ (T または d_ref<T>) は、非定数引数として関数に使用することができません (定数引数としては使用できます)。この間違った使用法に起因するコンパイル・エラーに対処することができた場合でも、表面上は値が変更されていてもコレクション内の値は変更されません。コレクションの要素の値を適切に変更するには、テンポラリを使用し、その後プロキシ・オブジェクトの要素に変更された値を割り当てます。以下はその例です。
d_ref<Sample_Person> p = (*list)[2];
change_to_someone_else(p);
(*list)[2] = p;
しかし、calc_some_value() がその引数を変更しなければ、以下も適切に動作します。
int val = calc_some_value((*list)[2]);
コレクション・プロキシのデータ
C++ 標準ライブラリ・フレームワークに適合するためには、コレクションのプロキシはデータを持つ必要があります。つまり、同じコレクションの 2 種類のプロキシはサーバ上のデータ、およびコレクションの表記を変更しますが、お互いについて関知しないため、同期がとれない可能性があります。同じタイプのプロキシ・オブジェクト経由でコレクションにアクセスしている場合は、この問題は発生しません (通常はこの用法)。しかし、そのタイプが異なる場合は、発生する恐れがあります。
ストリームの使用法
Caché を使用すると、文字形式かバイナリ形式のいずれかの文字列を持つストリームというプロパティを生成できます。文字ストリームは長いテキスト文字列です。例えば、データ入力画面の自由形式テキスト・フィールドに入力された内容などがこれにあたります。バイナリ・ストリームはイメージ・ファイルやサウンド・ファイルを指しており、他のデータベース・システムの BLOB (binary large object) に類似しています。ストリームにデータを書き込んだり、ストリームからデータを読み取ったりする場合、Caché によってストリーム内での位置が監視されるので、前方や後方へ移動することができます。
以下に、Caché ストリーム・オブジェクトを作成および操作する簡単なプログラムを示します。
#include <database.h>
#include <streams.h>
int main(){
// establish the physical connection to Cache'
Db_err conn_err;
d_connection conn = tcp_conn::connect("localhost[1972]:Samples",
"_SYSTEM", "SYS", 0, &conn_err);
// establish the logical connection to Cache'
// database and create a low level stream object.
db(conn);
d_ref<d_char_stream> stream = d_char_stream::create_new(&db);
// create an IOStreams extension stream object, put
// "Hello, World!" in the stream, and rewind the stream
d_iostream io(stream);
io << "Hello, World!";
io.rewind();
// read each word and copy it to standard output
std::string s;
while (io.good()) {
io >> s;
std::cout << s << ' ';
}
std::cout << '\n';
return 0;
}
リレーションシップの使用法
Caché 内と同様に、リレーションシップはプロパティとして扱われます。例えば、Sample.EmployeeOpens in a new tab と Sample.CompanyOpens in a new tab 間のリレーションシップからは、以下のようなコードが生成されます。
class Sample_Employee : public Sample_Person {
// code
virtual d_ref<Sample_Company> getCompany() const;
virtual void setCompany(const d_ref<Sample_Company>&);
// code
};
class Sample_Company : public Persistent_t {
// code
virtual d_ref< d_relationship<Sample_Employee> > getEmployees() const;
virtual void setEmployees(const d_ref< d_relationship<Sample_Employee> >&);
// code
};
d_relationship<T> クラス・テンプレートは、反復子 begin() および end() と、逆反復子 rbegin() および rend() をサポートする標準コンテナです。以下に、このリレーションシップを使用して従業員リストにアクセスする簡単なプログラムを示します。
#include "Sample_Company.h"
#include "Sample_Employee.h"
#include <algorithm>
class Print_person : public std::unary_function<d_ref<Sample_Person>, int> {
private:
std::ostream& out;
public:
explicit Print_person(std::ostream& o)
: out(o)
{}
result_type operator()(argument_type p) const
{ out << p->getName() << std::endl; return 0; }
};
int main()
{
// establish the connection to Cache'
Db_err conn_err;
d_connection conn = tcp_conn::connect(
"localhost[1972]:Samples", "_SYSTEM", "SYS", 0, &conn_err);
Database db(conn);
d_ref<Sample_Company> obj = Sample_Company::openid(&db, L"1");
d_ref< d_relationship<Sample_Employee> > r = obj->getEmployees();
// print the names of all employees in the order they are
// stored in the relationship
std::for_each(r->begin(), r->end(), Print_person(std::cout));
std::cout << std::endl;
// print the names of all employees in the reverse order
std::for_each(r->rbegin(), r->rend(), Print_person(std::cout));
return 0;
}
クエリの使用法
Caché クエリは、タイプ d_query として処理されます。d_query は ODBC のフレームワークに当てはまるように設計されていますが、ダイナミック・クエリの単純で完全なインタフェースの背後にダイレクト ODBC 呼び出しを隠すことにより、さらに高いレベルの抽象化を行うことができます。クエリは、SQL 文の作成、パラメータの結合、クエリの実行、結果セットの検索のメソッドを持ちます。
Caché クエリの使用法の基本的な手順は、以下のとおりです。
-
作成
クエリの作成のメソッドは、以下のとおりです。
void prepare(const wchar_t* sql_query, int len);
ここで、sql_query は実行するクエリを表します。
-
パラメータの設定
パラメータに値を割り当てます。
template<typename D_TYPE> void set_par(int index, const D_TYPE& val);
この関数は、パラメータ index を val に設定します。この関数は、C++ バインディングのあらゆるデータ型に対応します。同じパラメータに対して、数回呼び出すこともできます。そのパラメータの前の値は、消去されます。新しい値は同じタイプである必要はありません。
-
実行
以下の関数は、クエリを実行します。すべてのパラメータが結合されるまでは、これを呼び出さないでください。
void execute();
-
フェッチ
取得可能なデータがあるかどうかを調べます。
bool fetch();
この関数は、結果セットから次の行を取得しようとします。これが成功した場合に True を、失敗した場合に False を返します。この関数は、データをフェッチしません。これ以上フェッチするデータがあるかどうかを確認するだけです。
-
データの検索
クエリの実行が成功すると、各レコードに対し 1 行ずつ結果セットを返します。各行のデータは、以下を呼び出して行を左から右に繰り返すことにより、アクセスできます。
void get_data(T* val);
T は、C++ バインディングのいずれのデータ型でもかまいません。d_string には、データの変換方法を指定できます。
void get_data(d_string* val, str_conv_t conv = NO_CONV);
既定では、データを変換しません (“NO_CONV” 値)。"CONV_TO_MB" はデータをマルチバイトに、"CONV_TO_UNI" はデータを Unicode に変換します。
各呼び出しの後、暗黙の反復子は次の列に移動します (したがって、get_data() を 2 回呼び出して、同じ列のデータに 2 回アクセスすることはできません)。これにより、実装はすべてのデータをクライアントに格納する必要がなくなります。そうでない場合は、クエリの使用が、大量のメモリによるオーバーヘッドを引き起こすことになります。データに対し、ランダム・アクセスが必要なアプリケーションは、行のすべてのデータを最初に読み取る必要があります。
以下を呼び出すと、1 列または複数の列をスキップできます。
void skip(int num_cols = 1)
以下を呼び出すと、次に処理される列のインデックスを取得できます。
int get_cur_idx();
以下は、Sample.Person にクエリを発行する簡単な関数です。
void example(Database& db)
{
d_query query(&db);
d_string name;
d_int id;
d_date dob;
const wchar_t* sql_query = L"select ID, Name, DOB from Sample.Person
where ID > ? and FavoriteColors = ? ";
int size = wcslen(sql_query);
query.prepare(sql_query, size);
query.set_par(1, 1);
query.set_par(2, "Blue", 4);
query.execute();
std::wcout << L"results from " << std::wstring(sql_query) << std::endl;
while (query.fetch())
{
query.get_data(&id);
query.get_data(&name);
query.get_data(&dob);
std::cout << std::setw(4) << id
~<< std::setw(30) << std::string(name)
~<< std::setw(20) << dob << std::endl;
}
std::cout << std::endl;
}
トランザクションの使用法
トランザクションの実行には、以下の 2 つのオプションがあります。
-
Database クラス・メソッド — 標準の入れ子になったトランザクションを実行します。
-
Transaction クラス・メソッド — 入れ子になったトランザクションは許可されませんが、例外発生時の自動的なロールバック動作が保証されます。
データベース・クラス・メソッドの使用法
入れ子になったトランザクションは、Database クラスの以下のメソッドを使用して実行できます (LC_Database クラスからも継承されます)。
-
tstart() — 入れ子になったトランザクションの新しいレベルを開始します。
-
tcommit() — トランザクションの現在のレベルをコミット済みとしてマークします。最も外側のレベルをコミットすると、トランザクション全体がコミットされます。
-
trollback() — トランザクションのすべてのレベルをロールバックします。
-
tlevel() — 現在のトランザクション・レベルを返します。
以下はその例です。
for (i = 0; i < numPersons; i++) {
db->tstart()
// perform the transaction
{...}
if (goodtransaction)
db->tcommit();
else
db->trollback();
}
プロキシ・オブジェクトの save()、insert()、update()、または delete_object() メンバ関数が呼び出されると、tstart() および tcommit() の各メソッドも暗黙的に呼び出されます。これにより、トランザクション範囲の一時的なロックと、エラー時のロールバック動作が保証されます。
トランザクション・クラス・メソッドの使用法
Transaction クラスでは、例外発生時の自動的なロールバック動作が保証されます。commit() または rollback() のいずれも呼び出されていないときに、Transaction オブジェクトが範囲外になると、そのトランザクションはロールバックされます。このクラスでは、入れ子になったトランザクションは許可されません。
Transaction メソッドの動作は以下のとおりです。
-
Transaction() — コンストラクタがトランザクションを開始します (tstart() の呼び出しを必要とする Database オブジェクトとは異なります)。
-
Transaction::commit() — トランザクションをコミットします。同じ Transaction オブジェクトに対して commit() を複数回呼び出しても何も実行されません (入れ子になったトランザクションの複数レベルでコミットを実行するために繰り返し呼び出すことのできる Database::tcommit() とは異なります)。
-
Transaction::rollback() — トランザクションをロールバックします。トランザクションがコミットまたはロールバックされる前に Transaction オブジェクトが範囲外になると、自動的に呼び出されます。
以下はその例です。
for (i = 0; i < numPersons; i++) {
Transaction tran(db);
// perform the transaction
{...}
// transaction will rolled back if an exception
// occurs before this point
if (goodtransaction)
tran->commit();
else
tran->rollback();
}
上記のように、Transaction オブジェクトは以下でインスタンス化する必要があります。
Transaction tran(db);
以下の方法は使用しません。
Transaction tran = new Transaction(db);
オブジェクトが new を使用してヒープから割り当てられている場合、そのオブジェクトは範囲外になっても自動的には破棄されないため、トランザクションはロールバックされません。
Light C++ バインディング・アプリケーションでは、プロジェクション・クラスのメンバ関数 save()、delete_object()、insert()、または update() 内で例外がスローされると、自動的にロールバックが発生します。Transaction クラスのインスタンスが例外のスローされた範囲内に自動変数として宣言されており、その範囲内で例外がキャッチされない限り、他のコンテキストでスローされた例外によってトランザクションが自動的にロールバックされることはありません。