『ZODB トランザクションを使う』
Created by mcdonc. Last modified on 2000/10/18.
「ZOPEのトランザクション・マネージャの利用」
ZODBやその他のトランザクション処理系データ・ストレージにおいてなされる作業はすべて、トランザクションという考え方を元にして行われる。トランザクション・マネージャは物理的にはZopeオブジェクト・データベース(ZODB)の一部であるのだが、おそらく、ZODBを実装していないデータ・ストレージにおいても、うまく動作するであろう。たとえば、ZSQLメソッドはZopeのトランザクション機構を利用して、ZODBのトランザクションをリレーショナル・データベースのトランザクションに結びつけているのである。したがって、Zopeのトランザクション・マネージャは、一つ、あるいは複数の、独立したデータ・ストレージ上で動作するものだといえる。get_transaction() というグローバルなアクセス関数によって、トランザクション・マネージャからトランザクション・オブジェクトを獲得することができる。このオブジェクトを操作すると、登録されたすべてのデータ・ストレージに影響が及ぶ。つまり、獲得したトランザクション・オブジェクトに対してコミットすると、そのZODBだけでなく、そのトランザクション機構に登録されているすべてのデータ・ストレージに影響を与えるのである。
「Zopeはトランザクションをどのように利用しているか」
通常の操作において、Zopeパブリッシャーはトランザクションのことを、一回のwebリクエストの長さであると定義している。ZopeパブリッシャーはZODBのトランザクション・マネージャを利用して、トランザクションをコミットあるいはアボートしている。 リクエストがうまく渡されると、トランザクション・マネージャは「コミット(commit)』と呼ばれ、連携しているすべてのデータベースもコミットされる。もしリクエストに失敗すると(例えば、リクエスト中に例外が発生したりすると)、トランザクション・マネージャは「アボート(abort)」と呼ばれ、連携するすべてのデータベースは、それ以前の状態にロールバックされる。
Zopeのアプリケーションによって明示的にリクエストされないかぎり、一回のwebリクエストにおいて、サブトランザクションが使われることはない。
「トランザクション機構を手動で操作する」
アプリケーション開発者は、標準ではないトランザクション・ポリシーやサブトランザクションをサポートするために、トランザクション機構を手動で操作することがあるかもしれない。
トランザクション機構を手動で操作するためには、以下の三つの段階が必要となる。
・トランザクション・オブジェクトを獲得する。
・トランザクションを開始する。
・トランザクション・オブジェクトをコミット、アボートしたり、その他のアクションをする。
「トランザクション・オブジェクトを獲得する」
アプリケーション開発者は、(組み込みの) get_transaction() メソッドを呼び出すことによって、ZopeのPythonコードからトランザクション・オブジェクトを獲得することができる。(この関数は、ZODBパッケージがインポートされたときに、Pythonの組み込みネームスペースの中にインサートされる。) 以下にその例を示す。
t = get_transaction()
「トランザクションを開始する」
トランザクションは、ZODBオブジェクトを扱いはじめた時に自動的に開始される。もちろん、トランザクション・オブジェクトの begin() メソッドを呼び出すことによっても可能ではあるが、明示的にトランザクションを開始させる必要はない。明示的に新しいトランザクションを開始すると、現在のトランザクションで行っていた作業はすべて自動的にアボートされてしまう。以下に、トランザクションの開始の仕方を示す。
get_transaction().begin()
「トランザクション・オブジェクトに、コミットやアボートなどのアクションを行う」
一度トランザクション・オブジェクトを獲得すると、それに対して操作を行うことになる。トランザクション・オブジェクトは、commit(), abort(), note() の3つのインターフェースメソッドをサポートしている。
commit()
トランザクションをコミットする。
abort()
トランザクションをアボートする。
note()
現在のトランザクションに関して、トランザクション・ログに注釈を追加する。
以下に、(それ以前の作業に対して)トランザクションをコミットする例を示す。
ob = self.getOb()
ob.attr = foo
get_transaction().commit()
以下に、このトランザクションの同じ作業に対するアボートの例を示す。
ob = self.getOb()
ob.attr = foo
get_transaction().abort()
次は、トランザクションに注釈をつける例である。
ob = self.getOb()
ob.attr = foo
get_transaction().note(assign of foo to ob.attr was in this transaction)
「サブトランザクション」
一つのトランザクションの間に、トランザクション自体をコミットしたりアボートしたりすることなく、そのトランザクション中に行われた作業のある部分だけをコミットしたりロールバックしたりすることができる。それをサブトランザクションと呼んでいる。
サブトランザクションは、トランザクション・オブジェクトを獲得し、commit() や abort() メソッドを一つの真の値を渡して呼び出すことによって、行われる。
サブトランザクションのコミットの例である。
get_transaction().commit(1)
サブトランザクションをコミットすると、その時点まで行われていたトランザクションの作業全体が保存される。
サブトランザクョンのアボートの例。
get_transaction().abort(1)
サブトランザクションをアボートすると、トランザクションの開始時点から現在までコミットされていなかった作業、あるいは、最後にサブトランザクションがコミットされてから現在までコミットされていない作業のすべてが、アボートされてしまう。
データ・ストレージは明示的にサブトランザクションをサポートしなければならない。ほとんどのリレーショナル・データベースはサポートしていないが、ZODBはサブトランザクションをサポートしている。サブトランザクション内で行われた操作は、その手のリレーショナル・データベースでは定義されない。
「なぜサブトランザクションが必要なのか?」
通常、Zopeのトランザクションは、トランザクション中で修正が加えられたオブジェクトのリストをメモリの中に保持している。このオブジェクトのリストは、トランザクション中に多くのオブジェクトに対し多くの作業が行われると、かなり大きなものとなる。サブトランザクションはこのオブジェクトのリストのある部分をハードディスクに書き出し、トランザクションのリストに必要とされるメモリをその分だけ解放するのである。サブトランザクションを使うことによって、合計するとメモリの容量以上のサイズを必要とするようなオブジェクト群を扱うトランザクションが可能になるのである。
「参考サイト」
Zopeオブジェクト・データベースの紹介 :
http://www.zope.org/Members/jim/Info/IPC8/ZODB3/index.html
ZODB の HowTo?:
http://www.zope.org/Members/michel/HowTos/ZODB-How-To
ZODB の UML モデル:
http://www.zope.org/Documentation/Developer/Models/ZODB