トランザクションとロックについて

マルチユーザー・アプリケーションでは、多くのユーザーが同じデータに同時にアクセスする同時実行を制御する必要があります。制御しない場合、データが不適切に更新または変更される可能性があります。同時実行制御は、Transactionインタフェースにより管理します。このトピックでは、次のような情報管理システムの重要な要件が、トランザクションでどのように実現されるかについて説明します。

トランザクションでは、ロックを使用してデータへの同時アクセスを制御することにより、次の2つの重要なデータベースの目標を達成しています。

Business Components for Javaフレームワークは、次の機能および利点を提供するロック・モデルをサポートしています。

Business Components for Javaフレームワークを使用することにより、エンティティ・オブジェクトまたはビュー・オブジェクト内の行に対するロックを要求できます。エンティティ・オブジェクトの行をロックした場合、その行にデータベース・ロックが行われます。ビュー・オブジェクトの行をロックすると、フレームワークにより、そのビュー・オブジェクトの行で使用されているエンティティ行に対するロックが要求されます。

Business Components for Javaでは、次の表に示すロック・スタイルがサポートされています。どのスタイルも、データのスケーラビリティ、パフォーマンスおよび一貫性の点で長所と短所があります。たとえば、データベース・ロックが早いと(即時ロック)、スケーラビリティは低下しますが、データの非一貫性は起こりにくくなります。ロック・スタイルを変更した場合、その変更は後続のロックにのみ影響します。すでに実行されているロックは変更されません。

ロック・スタイル

説明

即時ロック

ロックは、最初のクライアントからの変更が行われる直前に、基礎となる行に対して自動的に行われます。これはアプリケーション・モジュールのデフォルト・スタイルです。Transaction.LOCK_PESSIMISTIC定数で表されます。

コミット時ロック

ロックは、変更がコミットされた時点で、基礎となる行に対して自動的に行われます。Transaction.LOCK_OPTIMISTIC定数で表されます。

明示的ロック

ロックは、クライアントからの明示的なコールにより、適切な時期に手動で行われます。ロックがコールされない場合、行がサーバーにフラッシュされた際に取得されたデータベース・ロックのみが取得されます。Transaction.LOCK_NONE定数で表されます。

次のコード例は、即時ロック・モードを示しています。

    if ( myEntity.getPostState() != Entity.STATUS_NEW
       && myEntity.getDBTransaction().getLockingMode()
         == Transaction.LOCK_PESSIMISTIC
       && !myEntity.isLocked() )
    {
	  myEntity.lock();
	}
	return myEntity;
	

ロックの失敗について

ロックは、次のような場合に失敗します。

いずれの場合も、異なるタイプのエラーによって問題が示されます。これにより、上位レベルのコール側は、そのエラーを示し、操作を再試行することもできます。

ロックの解放

特定のオブジェクトに対してロックが行われた後、そのオブジェクトはトランザクションで使用されるオブジェクトのリストに追加されます。トランザクションによりコミットまたはロールバックの操作が実行された後、トランザクションで使用される各オブジェクトには操作の結果が通知されます。各オブジェクトには、この通知サイクルの間保持可能な、ロック・インジケータ・フラグなどの内部状態を解放する機会が与えられます。

ロックとコンポジットについて

子エンティティ・オブジェクトを変更しようとすると、ビジネス・ロジック層は親エンティティ・オブジェクトをロックします。最上位の親エンティティ・オブジェクトが正常にロックされないかぎり、子エンティティ・オブジェクトは変更できません。たとえば、明細品目が含まれる注文の場合、ユーザーが明細品目の変更を開始すると、他のユーザーが注文やその品目を変更できないように注文全体がロックされます。これはロック・モードの設定よりも優先されます。

この動作は、メソッドlockTopLevelEntity()をオーバーライドすることによって変更できます。

行レベルのロックについて

行レベルAPIでは、選択されているロック・スタイルに関係なく、適切な時点でlockをコールすることにより、ビューおよびエンティティの行を明示的にロックできます。

特定の行オブジェクトに対して最初のlockがコールされた後、対応するデータベース・トランザクションによりcommitまたはrollback操作が実行されないかぎり、それ以降のコールは無視されます。これは、ロックがこれらのタイミングで自動的に解放されるためです。

ロックのコールは、次のような多くの理由で失敗します。

いずれの場合も例外がスローされ、問題が発生したことが示されます。これらの例外は、列の値の変更など、ロックが暗黙的に行われる場合があるため、前述の状況以外でも発生することがあります。

エンティティ行には、次のような、ロック状況をテストするためのメソッドが用意されています。

/**
* Is the Row locked?
**/
public boolean isLocked()