マルチユーザー・アプリケーションでは、多くのユーザーが同じデータに同時にアクセスする同時実行を制御する必要があります。制御しない場合、データが不適切に更新または変更される可能性があります。同時実行制御は、Transaction
インタフェースにより管理します。このトピックでは、次のような情報管理システムの重要な要件が、トランザクションでどのように実現されるかについて説明します。
データの読取りおよび変更は、一貫した形式で行う必要があります。
マルチユーザー・システムのデータ同時実行性を最大にする必要があります。
クライアントからの生産性を最大にするため、高パフォーマンスが必要とされます。
トランザクションでは、ロックを使用してデータへの同時アクセスを制御することにより、次の2つの重要なデータベースの目標を達成しています。
あるユーザーが表示または変更しているデータを、データの処理が完了するまで別のユーザーが変更できないことを保証する、一貫性
データベースのデータおよび構造が、行われたすべての変更の内容を正しい順序で反映していることを保証する、整合性
Business Components for Javaフレームワークは、次の機能および利点を提供するロック・モデルをサポートしています。
非一貫性が検出された場合も、ロックされます。
非一貫性が、データのDELETEによるものか、またはUPDATEにより発生したものかが判別されます。
元のデータ列を、ビジネス・ロジック層サーバーにおいて比較できます。
非一貫性が検出された場合、新たなラウンドトリップをせずに、非一貫性を修正するためのデータが取得されます。
Business Components for Javaフレームワークを使用することにより、エンティティ・オブジェクトまたはビュー・オブジェクト内の行に対するロックを要求できます。エンティティ・オブジェクトの行をロックした場合、その行にデータベース・ロックが行われます。ビュー・オブジェクトの行をロックすると、フレームワークにより、そのビュー・オブジェクトの行で使用されているエンティティ行に対するロックが要求されます。
Business Components for Javaでは、次の表に示すロック・スタイルがサポートされています。どのスタイルも、データのスケーラビリティ、パフォーマンスおよび一貫性の点で長所と短所があります。たとえば、データベース・ロックが早いと(即時ロック)、スケーラビリティは低下しますが、データの非一貫性は起こりにくくなります。ロック・スタイルを変更した場合、その変更は後続のロックにのみ影響します。すでに実行されているロックは変更されません。
ロック・スタイル |
説明 |
---|---|
即時ロック |
ロックは、最初のクライアントからの変更が行われる直前に、基礎となる行に対して自動的に行われます。これはアプリケーション・モジュールのデフォルト・スタイルです。 |
コミット時ロック |
ロックは、変更がコミットされた時点で、基礎となる行に対して自動的に行われます。 |
明示的ロック |
ロックは、クライアントからの明示的なコールにより、適切な時期に手動で行われます。ロックがコールされない場合、行がサーバーにフラッシュされた際に取得されたデータベース・ロックのみが取得されます。 |
次のコード例は、即時ロック・モードを示しています。
if ( myEntity.getPostState() != Entity.STATUS_NEW
&& myEntity.getDBTransaction().getLockingMode()
== Transaction.LOCK_PESSIMISTIC
&& !myEntity.isLocked() )
{
myEntity.lock();
}
return myEntity;
ロックは、次のような場合に失敗します。
リソースが別のユーザーにより使用されている場合
リソースがデータベースから削除された場合
エンティティ・キャッシュに移入された後、リソースが変更された場合
一般的なSQLエラーの状態(データベースの停止など)
いずれの場合も、異なるタイプのエラーによって問題が示されます。これにより、上位レベルのコール側は、そのエラーを示し、操作を再試行することもできます。
特定のオブジェクトに対してロックが行われた後、そのオブジェクトはトランザクションで使用されるオブジェクトのリストに追加されます。トランザクションによりコミットまたはロールバックの操作が実行された後、トランザクションで使用される各オブジェクトには操作の結果が通知されます。各オブジェクトには、この通知サイクルの間保持可能な、ロック・インジケータ・フラグなどの内部状態を解放する機会が与えられます。
子エンティティ・オブジェクトを変更しようとすると、ビジネス・ロジック層は親エンティティ・オブジェクトをロックします。最上位の親エンティティ・オブジェクトが正常にロックされないかぎり、子エンティティ・オブジェクトは変更できません。たとえば、明細品目が含まれる注文の場合、ユーザーが明細品目の変更を開始すると、他のユーザーが注文やその品目を変更できないように注文全体がロックされます。これはロック・モードの設定よりも優先されます。
この動作は、メソッドlockTopLevelEntity()
をオーバーライドすることによって変更できます。
行レベルAPIでは、選択されているロック・スタイルに関係なく、適切な時点でlock
をコールすることにより、ビューおよびエンティティの行を明示的にロックできます。
特定の行オブジェクトに対して最初のlock
がコールされた後、対応するデータベース・トランザクションによりcommit
またはrollback
操作が実行されないかぎり、それ以降のコールは無視されます。これは、ロックがこれらのタイミングで自動的に解放されるためです。
ロックのコールは、次のような多くの理由で失敗します。
リソースが別のユーザーに使用されている場合
リソースがデータベースから削除された場合
エンティティ・キャッシュに移入された後、リソースが変更された場合
一般的なSQLエラーの状態(データベースの停止など)
いずれの場合も例外がスローされ、問題が発生したことが示されます。これらの例外は、列の値の変更など、ロックが暗黙的に行われる場合があるため、前述の状況以外でも発生することがあります。
エンティティ行には、次のような、ロック状況をテストするためのメソッドが用意されています。
/**
* Is the Row locked?
**/
public boolean isLocked()