開発者リファレンス : プログラミング方法の概要 : Programmer's Guide : データの管理
  
このページをシェアする                  
データの管理
以下のトピックでは、データの管理について説明します。
データ管理の概要
テーブル間の関係の定義
キー
参照制約
サンプル データベースの参照整合性
データベース セキュリティの管理
並行制御
Zen データベースのアトミシティ
データ管理の概要
この章では、以下の項目について説明します。
テーブル間の関係の定義
データベース セキュリティの管理
並行性の制御
SQL データベースのアトミシティ
多くの場合、SQL ステートメントを使用して、これらのデータベース管理作業を行うことができます。
SQL Data Manager を使用して SQL ステートメントを入力することもできます。SQL Data Manager の使用方法の詳細については、『Zen User's Guide』を参照してください。
テーブル間の関係の定義
Zen と共に参照整合性(RI)を使用して、データベース内でそれぞれのテーブルがどのように関係しているかを定義することができます。RI は、あるテーブルの列(または列のグループ)が別のテーブルの列(または列のグループ)を参照しているとき、これらの列に対する変更は同期することを保証します。RI はテーブル間の関係を定義する一連の規則を提供します。これらの規則は参照制約として知られています(参照制約は簡略的に関係とも呼ばれます)。
データベース内のテーブルに参照制約を定義すると、MicroKernel エンジンは、これらのテーブルにアクセスするすべてのアプリケーションにわたって制約を強制します。これにより、アプリケーションはテーブルを変更するごとに個別にテーブルの参照をチェックすることから解放されます。
RI を使用するにはデータベースに名前を付ける必要があります。いったん参照制約を定義すると、影響を受けるファイルはそれぞれデータベース名を含みます。誰かがファイルを更新しようとすると、MicroKernel エンジンはデータベース名を使用して適用できる RI 定義を含むデータ辞書を探し、その RI 制約に対して更新をチェックします。これにより Zen アプリケーションが RI を危うくすることを防止します。MicroKernel エンジンが参照整合性制約に合致しない更新を阻止するからです。
データベース内のテーブルに参照整合性を定義するには、CREATE TABLE および ALTER TABLE ステートメントを使用します。構文の情報については、『SQL Engine Reference』の次のトピックを参照してください。
CREATE TABLE
ALTER TABLE
参照整合性の定義
次の定義は、参照整合性を理解するのに役立ちます。
親テーブルは、外部キーによって参照される主キーを含むテーブルです。
親行は、主キーが外部キー値と一致する、親テーブル内にある行です。
あるテーブルの行の削除により 別のテーブルの行の削除が起こる場合、連鎖削除テーブルが発生します。テーブルが連鎖削除かどうかは次の条件により決定されます。
自己参照テーブルはそれ自体に対し連鎖削除になります。
従属テーブルは、削除規則に関係なく、常にその親に対して連鎖削除です。
あるテーブルの親テーブルとさらにその親テーブルの削除規則が CASCADE の場合、このテーブルと、親の親テーブルは連鎖削除になります。
従属テーブルは、1 つまたは複数の外部キーを持つテーブルです。これらの外部キーは、それぞれ同一または異なるテーブルの主キーを参照することができます。従属テーブルは複数の外部キーを持つことができます。
従属テーブルの外部キー値は、それぞれ関連する親テーブルに一致する主キー値がある必要があります。言い換えると、外部キーが特定の値を持つ場合、外部キーの親テーブル内のいずれかの行の主キー値がその値を持つ必要があります。
従属テーブルに行を挿入する試みは、次の場合に失敗します。それぞれの参照制約の親テーブルが、挿入しようとする従属テーブルの外部キー値と一致する主キー値を持たない場合です。外部キーが現在参照している親テーブルの行を削除しようとすると、参照制約をどのように定義したかによって、失敗するか、または従属行まで削除することになります。
従属行は、従属テーブル内の行で、その外部キー値は、関連付けられている親行の一致する主キー値に依存します。
孤立行は、親テーブルの主キーに対応するインデックスに存在しない外部キー値を持つ、従属テーブルの行です。従属キー値は対応する親キー値を持ちません。
参照は、主キーを参照する外部キーです。
参照パスは、従属テーブルと親テーブルの間の参照で構成される特定のセットです。
子孫は、参照パス上にある従属テーブルです。これは、パスの元の親テーブルから削除された 1 つまたは複数の参照です。
自己参照テーブルは、それ自体の親テーブルであり、その主キーを参照する外部キーを含むテーブルです。
サイクルは、あるテーブルの親テーブルが同時にそのテーブルの子テーブルにもなっている参照パスです。
キー
RI を使用するには、キーを定義する必要があります。キーには、主キーと外部キーの 2 つのタイプがあります。
主キーとは、テーブル内の各行を一意に識別する列または列のグループのことです。キー値は常に一意であるため、行の重複の検出または防止に使用することができます。
外部キーは、テーブルの関係における従属テーブルと親テーブルで共通の列または列のセットです。親テーブルは、主キーとして定義された一致する列または列のセットを持つ必要があります。外部キーは親テーブルの主キーを参照します。これは、1 つのテーブルから別のテーブルへの列の関係で、MicroKernel エンジンに参照制約を行わせる機能を提供します。
主キー
優れた主キーは次のような特性をもちます。
これは必須で、非ヌル値を格納する必要があります。
一意であること。たとえば、Student または Faculty テーブルの ID 列は、それぞれ一意に定義されているため、優れたキーと言えます。人の名前を使用することは、複数の人が同一名である可能性があるため、あまり実用的ではありません。また、データベースは名前のバリエーション(たとえば、Andrew に対する Andy や Jennifer に対する Jen)を同一のものとして検出することができません。
安定性があること。学生の ID は、個人を一意に識別するだけでなく、変更される可能性が低いため、優れたキーと言えます。それに対し、人の名前は変わる可能性があります。
短いこと。文字数が少ないこと。小さな列はストレージのわずかなスペースしか占めず、データベースの検索が早く、入力ミスが少なくなります。たとえば、9 桁の ID 列は 30 文字の名前列より簡単にアクセスできます。
主キーの作成
テーブルに外部キーを作成することにより、参照制約を作成します。ただし、外部キーを作成する前に、外部キーが参照する親テーブルの主キーを作成する必要があります。
テーブルは主キーを 1 つだけ持つことができます。次のいずれかを使用して主キーを作成することができます。
CREATE TABLE ステートメントの PRIMARY KEY 句
ALTER TABLE ステートメントの ADD PRIMARY KEY 句
次の例は、サンプル データベースの Person テーブルに、主キー ID を作成します。
ALTER TABLE Person
ADD PRIMARY KEY (ID);
主キーを作成する場合、Zen は一意、非ヌル、変更不可能なインデックスを使用して主キーをテーブル上に実装することを忘れないでください。指定した列にそのようなインデックスが存在しない場合、Zen は、これらの特性を持ち、主キー定義に指定された列を含む、名前のないインデックスを追加します。
主キーの削除
主キーを削除できるのは、それに依存する外部キーをすべて削除した後だけです。テーブルから主キーを削除するには、ALTER TABLE ステートメントで DROP PRIMARY KEY 句を使用します。テーブルには 主キーが 1 つしかないため、次の例に示すように、主キーを削除するときに列名を指定する必要はありません。
ALTER TABLE Person
DROP PRIMARY KEY;
主キーの変更
テーブルの主キーを変更するには、次の手順を行います。
1 ALTER TABLE ステートメントで DROP PRIMARY KEY 句を使用して既存の主キーを削除します。
メモ:このことにより、主キーに使用された列やインデックスが削除されることはありません。主キー定義を削除するだけです。主キーを削除するには、その主キーを参照する外部キーがあってはいけません。
2 ALTER TABLE ステートメントで ADD PRIMARY KEY 句を使用して新しい主キーを作成します。
外部キー
外部キーは、テーブルの関係における従属テーブルと親テーブルで共通の列または列のセットです。親テーブルは、主キーとして定義された一致する列または列のセットを持つ必要があります。外部キーを作成すると、従属テーブルとその親テーブルの間に参照制約またはデータ リンクを作成することになります。この参照制約には親テーブルの従属行を削除または更新する規則を含めることができます。
外部キー名は省略可能です。外部キー名を指定しない場合、Zen は外部キー定義の最初の列の名前を使用して外部キーを作成しようとします。外部キーとその他のデータベース要素の名前付け規則については、名前付け規則を参照してください。
Zen のキーワードは予約語であるため、これらはデータベース要素の名前付けには使用できません。キーワードの一覧は、『SQL Engine Reference』の SQL の予約語を参照してください。
既存のテーブルに外部キーを作成する
既存のテーブルに外部キーを作成するには、次の手順を行います。
1 参照する親テーブルに主キーが存在することを確認します。
主キーと外部キーのすべての列は同一のデータ型と長さで、一連の列の順序は両方の定義で同じである必要があります。
2 Zen は、外部キー定義に指定された列または列のグループに非ヌル インデックスを作成します。テーブル定義に既にそのようなインデックスが存在する場合、Zen はそのインデックスを使用します。存在しなければ、Zen は非ヌルで、一意ではなく、変更可能なインデックス属性を持つ名前のないインデックスを作成します。
3 ALTER TABLE ステートメントで ADD CONSTRAINT 句を使用して新しい外部キーを作成します。
たとえば、次のステートメントは、サンプル データベースの Faculty テーブルの Dept_Name 列に Faculty_Dept という名前の外部キーを作成します。外部キーは Department テーブルに作成された主キーを参照し、削除制限規則を指定します。
ALTER TABLE Faculty
ADD CONSTRAINT Faculty_Dept FOREIGN KEY (Dept_Name)
REFERENCES Department
ON DELETE RESTRICT;
テーブル作成時に外部キーを作成する
テーブル作成時に外部キーを作成するには、次の手順を行います。
1 参照する親テーブルに主キーが存在することを確認します。
主キーと外部キーのすべての列は同一のデータ型と長さで、一連の列の順序は両方の定義で同じである必要があります。
2 Zen は、外部キー定義に指定された列または列のグループに非ヌル インデックスを作成します。テーブル定義に既にそのようなインデックスが存在する場合、Zen はそのインデックスを使用します。存在しなければ、Zen は非ヌルで、一意ではなく、変更可能なインデックス属性を持つ名前のないインデックスを作成します。
3 CREATE TABLE ステートメントを使用してテーブルを作成し、FOREIGN KEY 句を含めます。
たとえば、次のステートメントは、Course テーブルの Dept_Name 列に Course_in_Dept という外部キーを作成します。
CREATE TABLE Course
(Name CHAR(7) CASE,
Description CHAR(50) CASE,
Credit_Hours USMALLINT,
Dept_Name CHAR(20) CASE)#
ALTER TABLE Course
ADD CONSTRAINT Course_in_Dept
FOREIGN KEY (Dept_Name)
REFERENCES DEPARTMENT(Name)
ON DELETE RESTRICT
外部キーの削除
テーブルから外部キーを削除するには、ALTER TABLE ステートメントで DROP CONSTRAINT 句を使用します。テーブルには複数の外部キーがある可能性があるため、外部キーの名前を指定する必要があります。
ALTER TABLE Course
DROP CONSTRAINT Course_in_Dept;
参照制約
参照制約を定義するデータベースは次の条件を満たしている必要があります。
データベースにはデータベース名がある必要があります。
データベースは、単一のワークステーション ドライブまたは単一のマップされたネットワーク ドライブに存在する必要があります。
データ ファイルは 6.x 以降の MicroKernel エンジン形式である必要があります。
5.x 以降のデータ ファイルを 6.x または 7.x 形式へ変換する方法については、『Advanced Operations Guide』を参照してください。
データベースが参照整合性をサポートするためには、外部キーの概念をサポートする必要があります。外部キーは 1 つのテーブル(従属テーブルと呼ばれる)の 1 つの列または一連の列で、別のテーブル(親テーブルと呼ばれる)の主キーを参照するのに使用します。RI 規則はすべての外部キー値が有効な主キー値を参照することを必要とします。たとえば、学生は存在しない講座に登録することはできません。
CREATE TABLE または ALTER TABLE ステートメントを使用して、名前付きデータベースのテーブルにキーを定義することができます。次のセクションでは、キーの作成と変更方法について説明します。また、参照制約の例も用意されています。
データベースに参照制約を定義した後は、更新を行うアプリケーションは参照規則に従わないと失敗します。たとえば、アプリケーションが対応する親行を親テーブルに挿入する前に従属テーブルに行を挿入しようとすると、これは失敗します。詳細については、参照整合性規則を参照してください。
メモ:ファイルに参照制約が定義されている場合、これはバウンド データ ファイルです。ユーザーがこのファイルに Btrieve を使用してアクセスしようとすると、アクセスできますが、RI 制約の範囲内のアクションを実行するのに限られます。バウンド データ ファイルの詳細については、データベース権限の理解を参照してください。
参照整合性規則
データベース テーブルに参照制約を定義した場合、従属テーブルの行の挿入と更新、および親テーブルの行の更新と削除に一定の規則が適用されます。Zen は、次のように制限規則とカスケード規則をサポートします。
従属テーブルへの挿入-各外部キー定義の親テーブルは、挿入する外部キーに対応する主キー値を持つ必要があります。親テーブルが対応する値を持たない場合、その挿入処理は失敗します。
従属テーブルの更新-各外部キー定義の親テーブルは、外部キーに対応する主キー値(外部キーの新しい値)を持つ必要があります。親テーブルが対応する値を持たない場合、その更新処理は失敗します。
親テーブルでの更新-これは許可されません。主キー値を更新することはできません。このような処理を実行するには、更新したい行を削除し、その後新しいキー値を持つ同一行を挿入します。
親テーブルでの削除-この処理についてカスケード規則または制限規則のいずれかを指定することができます。カスケードとは、従属テーブルが、削除される主キー値に一致する外部キー値を持つ場合、その一致する値を持つ行がすべて従属テーブルから削除されることを意味します。
制限規則とは、従属テーブルが、削除される主キー値と一致する外部キーを持つ場合、親テーブルの削除処理が失敗することを意味します。カスケード処理は再帰的です。従属テーブルが、カスケード外部キーの親テーブルで主キーを持つ場合、処理はその一連のデータで繰り返されます。
挿入規則
挿入規則は制限規則です。挿入される行の外部キーは、それぞれ親テーブルの主キー値と等価である必要があります。親テーブルは、挿入しようとする行の外部キーの親行を持っている必要があり、そうでない場合は挿入は失敗します。Zen は、MicroKernel エンジンが、従属テーブルに自動的に挿入規則を適用するようにします。
 
更新規則
更新規則は制限規則でもあります。外部キー値は、親テーブルの対応する主キー値に更新される必要があります。親テーブルが外部キー値に対応する親行を持たない場合、更新は失敗します。
テーブルに外部キーを定義する際に明示的に更新規則として制限規則を指定することもできますが、指定しなかった場合、Zen は MicroKernel エンジンに対しデフォルトでこの規則を順守させます。
削除規則
外部キーを定義する際に、削除規則として制限またはカスケードを明示的に指定することができます。明示的に削除規則を指定しなかった場合、Zen は削除規則として制限をデフォルトと見なします。
削除規則として制限を指定した場合、Zen は MicroKernel エンジンに、親テーブルから削除しようとする行のそれぞれについて、その行が別のテーブルの外部キーの親行であるかどうかを調べさせます。親行である場合、Zen はステータス コードを返し、その行を削除しません。その親行を削除する前に、まず参照テーブルの対応する行をすべて削除する必要があります。
削除規則としてカスケードを指定した場合、Zen は MicroKernel エンジンに、親テーブルから削除しようとする行のそれぞれについて、その行が別のテーブルの外部キーの親行であるかどうかを調べさせます。次に、MicroKernel エンジンはそのテーブルの子孫についてそれぞれ削除規則をチェックします。子孫のいずれかの削除規則が制限である場合、削除は失敗します。すべての子孫の削除規則がカスケードである場合、Zen は元の親テーブルへの参照パス上のすべての従属行を削除します。
次のガイドラインは、外部キーの削除規則を決定します。
2 つ以上のテーブルのサイクルでは、テーブルそれ自体に対して連鎖削除できません。したがって、サイクル内の少なくとも 2 つの従属テーブルはカスケード削除規則であってはいけません。
1 つのテーブルから別のテーブルへのすべてのパスで最後の削除規則は同じである必要があります。
外部キーの削除規則がカスケードの場合、外部キーを含むテーブルは、削除トリガーが定義されていてはいけません。
外部キーを持つテーブルに削除トリガーが定義されている場合、削除規則は制限規則である必要があります。
Zen はこれらのガイドラインを参照制約の定義されているデータベース上で強制します。これらのガイドラインに違反する削除規則を宣言しようとすると、Zen はエラーの発生を示すステータス コードを返します。
Zen は、テーブルから従属行を削除する際、発生し得る例外を回避するために削除規則のガイドラインを強制します。これらのガイドラインがなければ発生する例外を次に示します。
連鎖削除サイクルの例外
2 つ以上のテーブルのサイクルでは、テーブルそれ自体に対して連鎖削除できません。したがって、サイクル内の少なくとも 2 つの従属テーブルは制限削除規則である必要があります。
次のステートメントを実行するとします。
DELETE FROM Faculty
Faculty と Department テーブルの間の関係により、Faculty からの行の削除は、まず Faculty から、次に Department から行を削除します。Department の名前の制限規則により、ここでカスケード削除は停止します。
Zen が Faculty テーブルから行を削除する順によって、結果に矛盾が生じることがあります。ID が 181831941 の行を削除しようとすると、その削除処理は失敗します。Department の Name 列 の制限規則により、Zen は、主キーの値が Mathematics と等しい Department テーブルの最初の行を削除することができません。これは、Faculty の 2 番目の行がこの行の主キーを参照し続けるためです。
そうではなく、Zen が、主キーが 179321805 と 310082269 に等しい Faculty の行を最初に削除した場合、Faculty と Department のすべての行が削除されます。
 
この例の DELETE ステートメントの結果には一貫性があるので、行は削除されません。
複数のパスにおける例外
複数の連鎖削除パスからの削除規則は同一である必要があります。図 2 はこのガイドラインを使用しないと発生する可能性のある 1 つの例外を示しています。図中の矢印は従属テーブルを指しています。
図 2 複数のパスの例外
Faculty は Room に対し、異なる削除規則を持つ複数の連鎖削除パスで連鎖削除になっています。次のステートメントを実行するとします。
DELETE FROM Room
WHERE Building_Name = 'Bhargava Building'
AND Number = 302;
操作が成功するかどうかは、Zen が Faculty と Department の削除規則を確実にするため、これらにアクセスする順序に依存します。
最初に Faculty にアクセスする場合、Room と Faculty の関係が制限規則であるため、削除処理は失敗します。
最初に Department にアクセスする場合、Department と Faculty で順次処理され、削除処理は成功します。
問題を回避するため、Zen は、Faculty へ導く両方のパスに対する削除規則が同一であることを保証します。
サンプル データベースの参照整合性
このセクションでは、サンプル データベースのテーブルと参照制約定義を説明します。
Course テーブルを作成する
次のステートメントは Course テーブルを作成します。
CREATE TABLE Course
(Name CHAR(7) CASE,
Description CHAR(50) CASE,
Credit_Hours USMALLINT,
Dept_Name CHAR(20))
Course テーブルに主キーを追加する
次のステートメントは、Course テーブルに主キー(Name)を追加します。
ALTER TABLE Course
ADD PRIMARY KEY (Name);
参照制約を使用して Student テーブルを作成する
次のステートメントは Student テーブルを作成し、参照制約を定義します。
CREATE TABLE Student
(ID UBIGINT,
PRIMARY KEY (ID),
Cumulative_GPA NUMERICSTS(5,3),
Tuition_ID INTEGER,
Transfer_Credits NUMERICSA(4,0),
Major CHAR(20) CASE,
Minor CHAR(20) CASE,
Scholarship_Amount DECIMAL(10,2),
Cumulative_Hours INTEGER)
CREATE UNIQUE INDEX Tuition_ID ON Student(ID)
 
ALTER TABLE Student ADD CONSTRAINT
S_Tuition
FOREIGN KEY (Tuition_ID)
REFERENCES Tuition
ON DELETE RESTRICT
データベース セキュリティの管理
Zen のセキュリティ機能を使用すると、特定のユーザーに対し、データ列の操作を制限することができます。これらの制限は、ユーザーがテーブルの特定の列しか見えないようにすることから、すべての列を見ることができるが更新できないようにすることまで、さまざまな範囲で行うことができます。Zen は、データベース許可について、オペレーティング システムのアクセス権利と権限に基づいて想定していません。デフォルトで、Zen を使用してデータベースにアクセスするすべてのユーザーは、データに読み書きする完全なアクセス権を持ちます。このアクセスを制限し、Zen を使用してデータベースを不当な更新またはアクセスから保護するために、データベース セキュリティを有効にし、定義する必要があります
Zen のセキュリティ ステートメントにより、データベースへのアクセスを制限する次の動作を行うことができます。
データベースのセキュリティを有効にする。
ユーザーおよびユーザー グループを識別し、パスワードを割り当てる。
ユーザーおよびユーザー グループに権限を付与する。
ユーザーおよびユーザー グループの権限を取り消す。
データベースのセキュリティを無効にする。
データベースに定義されたセキュリティに関する情報を取得する。
データベース権限の理解
41 は、ユーザーおよびユーザー グループに付与することができる権限を示しています。
表 41 データベース権
アクセス権
説明
Login
ユーザーがデータベースにログインすることを許可します。ユーザーとパスワードを作成するときにこのアクセス権を割り当てます。ただし、Login 権はユーザーがデータにアクセスすることは許可しません。ユーザーがデータにアクセスできるようにするには、ほかのアクセス権を割り当てる必要があります。ユーザー グループに Login 権を割り当てることはできません。
Create Table
ユーザーが新規テーブル定義を作成できるようにします。ユーザーはテーブル作成時に自動的にテーブルへのフル アクセス権を持ちますが、Master ユーザーは後でテーブルの読み取り、書き込み、変更のアクセス権を取り消すことができます。Create Table 権はグローバル権とも呼ばれます。このアクセス権がデータ辞書全体にも適用されるからです。
Select
ユーザーがテーブルの情報を照会することを許可します。Select 権は特定の列にもテーブル全体にも与えることができます。
Update
ユーザーに指定した列またはテーブルの情報を更新するアクセス権を与えます。Update 権は特定の列にもテーブル全体にも与えることができます。
Insert
ユーザーがテーブルに新しい行を追加できるようにします。Insert 権はテーブル レベルでのみ付与することができます。
Delete
ユーザーがテーブルから情報を削除できるようにします。Delete 権はテーブル レベルでのみ付与することができます。
Alter
ユーザーがテーブル定義を変更できるようにします。Alter 権はテーブル レベルでのみ付与することができます。
References
ユーザーがテーブルを参照する外部キー参照を作成できるようにします。References 権は、参照制約を定義するのに必要です。
All
Select、Update、Insert、Delete、Alter および References 権を含みます。
あるタイプのアクセス権を、データベース全体または特定のデータベース要素に割り当てることができます。たとえば、Update 権をユーザーまたはユーザー グループに割り当てた場合、これを一定のテーブルまたはテーブル内の列に制限することができます。それに反して、Create Table 権をユーザーまたはユーザー グループに割り当てた場合、そのユーザーまたはユーザー グループはデータベース全体に Create Table 権を持ちます。単一のテーブルまたは列に対して Create Table 権を適用することはできません。
Create Table と Login 権はデータベース全体に適用される一方、そのほかのアクセス権はすべてテーブルに適用されます。さらに、Select および Update 権をテーブル内の個々の列に適用することができます。
データベース セキュリティの確立
次の 9 つの手順はデータベースのセキュリティを確立する一般的な方法を表します。
1 セキュリティを確立するデータベースにログインします。
データベースへのログインの詳細については、『Zen User's Guide』を参照してください。
2 マスター ユーザーを作成し、SET SECURITY ステートメントを使用してマスター パスワードを指定することにより、データベースのセキュリティを有効にします。
マスターとしてセキュリティを有効にすると、マスター ユーザーの名前は Master(大文字小文字を区別)となり、セキュリティを有効にしたときに指定したパスワードがマスター パスワード(大文字小文字を区別)となります。詳細については、セキュリティの有効化を参照してください。
3 任意:PUBLIC グループに最低限のアクセス権のセットを定義します。
すべてのユーザーは自動的に PUBLIC グループに所属します。詳細については、PUBLIC グループにアクセス権を付与するを参照してください。
4 任意:CREATE GROUP ステートメントを使用してユーザー グループを作成します。
システムで必要な数のグループを作成することができます。ただし、1 人のユーザーは PUBLIC 以外は 1 つのグループにしか所属できません。詳細については、ユーザー グループの作成を参照してください。
5 任意:GRANT CREATETAB および GRANT(アクセス権)ステートメントを使用して、各ユーザー グループへのアクセス権を付与します。詳細については、ユーザー グループへのアクセス権の付与を参照してください。
6 GRANT LOGIN ステートメントを使用してユーザー名とパスワードを指定し、ユーザーに Login 権を付与します。選択すれば、各ユーザーをユーザー グループに割り当てることもできます。詳細については、ユーザーの作成を参照してください。
7 GRANT CREATETAB と GRANT(アクセス権)ステートメントを使用して、ユーザー グループのメンバーでない作成済みユーザーにアクセス権を与えます。詳細については、ユーザーへのアクセス権の付与を参照してください。
8 任意:不当な Btrieve アクセスからファイルを保護するために、データベースをバウンド データベースにします。バウンド データベースの詳細については、データベース権限の理解を参照してください。
セキュリティの有効化
セキュリティを有効にするには SET SECURITY ステートメントを使用できます。それに応え、Zen はマスター ユーザーを作成します。マスター ユーザーはデータベースに対し完全な読み書きのアクセス権を持ちます。SET SECURITY ステートメントで指定したパスワードはデータベースのマスター パスワードになります。
次の例はデータベースのセキュリティを有効にし、マスター ユーザーのパスワードに Secure を指定します。
SET SECURITY = Secure;
パスワードでは大文字小文字が区別されます。
セキュリティを有効にすると、Zen は X$User と X$Rights というシステム テーブルを作成します。セキュリティを有効にすると、マスター ユーザーを除くすべてのユーザーは、明示的にほかのユーザーを作成してログイン権を与えない限り、データベースにアクセスできません。
ユーザー グループとユーザーの作成
セキュリティを有効にした後、データベースは 1 人のユーザー(Master)と 1 つのユーザー グループ(PUBLIC)を持ちます。ほかのユーザーにデータベースへのアクセスを提供するには、マスター ユーザーとしてデータベースにログインし、名前とパスワードを使用してユーザーを作成します。またユーザーをユーザー グループに組織することもできます。
Zen はユーザー名の大文字小文字を区別します。したがって、マスター ユーザーとしてログインする場合、ユーザー名を Master と指定する必要があります。
ユーザー グループの作成
セキュリティ管理を単純化するために、ユーザーをユーザー グループに組織することができます。グループは、必要とするだけの数を、それぞれ異なるアクセス権および権限を持つように作成できますが、データベース内の各ユーザーは、1 つのグループにしか所属できません。ユーザーはいったんグループに所属すると、そのグループのアクセス権と PUBLIC グループのアクセス権のみを継承し、そのユーザーに与えられる個別のアクセス権は無視されます。1 つのグループ内のすべてのユーザーのアクセス権は同一です。ユーザーに固有のアクセス権を与えるには、そのユーザーのためだけの特別なグループを作成します。
ユーザー グループを作成するには、CREATE GROUP ステートメントを使用します。
CREATE GROUP Accounting;
一度に複数のユーザー グループを作成することもできます。
CREATE GROUP Accounting, Registrar, Payroll;
ユーザー グループ名は大文字と小文字を区別し、30 文字以内で、データベースに対して一意である必要があります。ユーザー グループ名を付ける規則の詳細については、『Advanced Operations Guide』を参照してください。
ユーザーの作成
データベースにユーザーを作成するとき、Zen は、対応するユーザー名とパスワードをデータベースのセキュリティ テーブルに記録します。ユーザーを作成するには GRANT LOGIN TO ステートメントを使用します。次の例は、ユーザー Cathy を作成し、パスワードとして Passwd を割り当てます。
GRANT LOGIN TO Cathy:Passwd;
メモ:Zen はパスワードを暗号化形式で格納します。したがって、X$User テーブルに照会してユーザーのパスワードを表示することはできません。
ユーザー作成時にユーザーをユーザー グループに割り当てることもできます。たとえば、ユーザー Cathy を Accounting グループに割り当てるには次のステートメントを使用します。
GRANT LOGIN TO Cathy : Passwd
IN GROUP Accounting;
ユーザー名とパスワードは大文字と小文字を区別します。ユーザー名とパスワードに対して許容される長さと文字については、『Advanced Operations Guide』の識別子の種類別の制限を参照してください。
アクセス権の付与
このトピックでは、ユーザー グループと個々のユーザーにアクセス権を与える方法を説明します。
PUBLIC グループにアクセス権を付与する
すべてのユーザーは自動的に PUBLIC グループに所属します。PUBLIC グループは特別なユーザー グループで、特定のデータベースのすべてのユーザーの最低限のアクセス権のセットを定義するのに使用します。PUBLIC グループに割り当てられたユーザーより少ないアクセス権を持つユーザーはいません。PUBLIC グループからユーザーを削除することはできません。PUBLIC グループに与えられているアクセス権をユーザーから取り消すことはできません。
デフォルトで、PUBLIC グループにはアクセス権が何もありません。PUBLIC グループのアクセス権を変更するには、GRANT(アクセス権)ステートメントを使用します。たとえば、次のステートメントはサンプル データベースのすべてのユーザーに、データベース内の Department、Course、Class テーブルを照会することを許可します。
GRANT SELECT ON Department, Course, Class
TO PUBLIC;
PUBLIC グループにアクセス権を与えたら、別のグループを作成してより高いレベルのアクセス権を定義することができます。ユーザーをグループに所属させないことによって、個々のユーザーに、ほかのユーザーまたはユーザー グループとは異なるアクセス権を追加することもできます。
ユーザー グループへのアクセス権の付与
ユーザー グループにアクセス権を割り当て、そのグループにユーザー名とパスワードを追加することができます。こうすると、各ユーザーのアクセス権を個々に割り当てる手間を省くことができます。また、グループにセキュリティ権を割り当てた場合、セキュリティ管理はより簡単になります。グループ全体に 1 度に新しいアクセス権を与えたり既存のアクセス権を取り消したりすることにより、多数のユーザーのアクセス権を変更することができるからです。
ユーザー グループにアクセス権を与えるには、GRANT(アクセス権)ステートメントを使用します。たとえば、次のステートメントは、Accounting グループのすべてのユーザーが、サンプル データベースの Billing テーブルの定義を変更することを許可します。
GRANT ALTER ON Billing TO Accounting;
メモ:Alter 権を与えることは、Select、Update、Insert、Delete 権を暗黙的に与えることを忘れないでください。
ユーザーへのアクセス権の付与
ユーザーを作成すると、そのユーザーはデータベースにログインできます。ただし、そのユーザーは、アクセス権を持つユーザー グループに所属させるか、そのユーザーにアクセス権を与えるかのいずれかをしなければ、データにアクセスすることはできません。
ユーザーにアクセス権を与えるには、GRANT(アクセス権)ステートメントを使用します。次の例は、ユーザー John に、サンプル データベースの Billing テーブルに行を挿入することを許可します。
GRANT INSERT ON Billing
TO John;
メモ:Insert 権を与えることは、Select、Update、Delete 権を暗黙的に与えることになります。
ユーザーとユーザーグループの削除
ユーザーを削除するには、REVOKE LOGIN ステートメントを使用します。
REVOKE LOGIN FROM Bill;
このステートメントは、データ辞書からユーザー Bill を削除します。ユーザーを削除すると、データベースのセキュリティを無効にしない限り、そのユーザーはデータベースにアクセスできません。
次の例のように、複数のユーザーを一度に削除することもできます。
REVOKE LOGIN FROM Bill, Cathy, Susan;
ユーザー グループを削除するには、次の手順に従います。
1 次の例のように、グループからすべてのユーザーを削除します。
REVOKE LOGIN FROM Cathy, John, Susan;
2 グループを削除するには、DROP GROUP ステートメントを使用します。次の例ではグループ Accounting が削除されます。
DROP GROUP Accounting;
アクセス権の取り消し
ユーザーのアクセス権を取り消すには、REVOKE ステートメントを使用します。次の例は、サンプル データベースの Billing テーブルから、ユーザー Ron の Select 権を取り消します。
REVOKE SELECT
ON Billing
FROM Ron;
セキュリティの無効化
データベースのセキュリティを無効にするには、次の手順を行います。
1 マスター ユーザーとしてデータベースにログインします。
2 次のように NULL キーワードを指定し、SET SECURITY ステートメントを発行します。
SET SECURITY = NULL;
データベースのセキュリティを無効にすると、Zen はデータベースからシステム テーブルの X$User と X$Rights を削除し、関連する DDF ファイルも削除します。
メモ:USER.DDF と RIGHTS.DDF データ辞書ファイルを単純に削除するだけではセキュリティを無効にすることはできません。これらを削除してデータベースにアクセスを試みると、Zen はエラーを返してデータベースへのアクセスを拒否します。
データベース セキュリティに関する情報の取得
データベース セキュリティを設定すると、Zen はシステム テーブル X$User と X$Rights を作成します。システム テーブルはデータベースの一部であるため、適切なアクセス権があれば、それらにクエリを実行できます。
各システム テーブルの内容のリファレンスは、『SQL Engine Reference』のシステム テーブルを参照してください。
並行制御
MicroKernel エンジンとその自動修復機能は、データベースの物理的な整合性を制御します。Zen は、MicroKernel エンジンのトランザクションとレコード ロック機能を使用して、論理的なデータの整合性を提供します。Zen は MicroKernel エンジンと共に、以下のタイプの並行制御を提供します。
トランザクションの分離レベル
明示的ロック
パッシブ コントロール
トランザクション処理
トランザクション処理は、単一のテーブル内であっても複数のテーブルにまたがっていても、論理的に関連する一連のデータベース変更を識別できるようにし、これを 1 つの単位として完了させるように要求します。トランザクション処理には 2 つの重要な概念があります。
作業の論理的な単位、つまりトランザクションは、データベースの整合性を確実にするために 1 つの操作として扱う必要のある別個の操作のセットです。トランザクション中にミスを犯したり、問題があった場合、ROLLBACK WORK ステートメントを発行して既に行った変更を元に戻すことができます。
たとえば、教務係は学生の口座と支払われた金額の記入を 1 度の操作で行い、それから 2 番目の操作で残額を更新します。これらの操作をグループ化することにより、学生の会計は正確になります。
ロック単位は、トランザクションが完了するまでほかのタスクがブロックされるデータの総数です(タスクは Zen のセッションです)。ロックにより変更しようとしているデータがほかのタスクによって変更されるのを防ぎます。ほかのタスクもデータを変更した場合、Zen は一貫性のある以前の状態にロール バックすることができません。したがって、トランザクション内では所定のロック単位に一度に 1 つのタスクしかアクセスできません。ただし、同一タスクに属する複数のカーソルはロック単位に同時にアクセスできます。
START TRANSACTION ステートメントがトランザクションを開始します。トランザクション中に完了したいすべてのステートメントを発行したら、COMMIT WORK ステートメントを発行してトランザクションを終了します。COMMIT WORK ステートメントはすべての変更を保存し、これを恒久的なものにします。
メモ:START TRANSACTION および COMMIT WORK は、ストアド プ ロシージャでのみ使用できます。これら 2 つの SQL ステートメントの詳細については、『SQL Engine Reference』を参照してください。
操作の 1 つでエラーが発生した場合、トランザクションをロールバックし、エラーを修正した後、再試行することができます。たとえば、いくつかのテーブルに関連する更新を行う必要があるけれども、更新の 1 つが失敗した場合、既に行った更新をロールバックすることができるので、データは矛盾しません。
2 つのタスクが ログイン セッションを共有していて、セッションを開いたタスクが、もう 1 つのタスクがトランザクションを完了する前にログアウトした場合にも Zen は自動的にロールバック操作を行います。
トランザクションの開始と終了
トランザクションを開始するには、ストアド プロシージャ内で START TRANSACTION ステートメントを発行します。トランザクション中に完了したいすべてのステートメントを発行したら、COMMIT WORK ステートメントを発行して変更をすべて保存し、トランザクションを終了します。
START TRANSACTION;
UPDATE Billing B
   SET Amount_Owed = Amount_Owed - Amount_Paid
   WHERE Student_ID IN
   (SELECT DISTINCT E.Student_ID
   FROM Enrolls E, Billing B
      WHERE E.Student_ID = B.Student_ID);
COMMIT WORK;
START TRANSACTION ステートメントの詳細については、『SQL Engine Reference』を参照してください。
ネストされたトランザクションへのセーブポイントの使用
SQL トランザクションでは、セーブポイントと呼ばれるマーカーを定義することができます。セーブポイントを使用すると、トランザクション内のセーブポイント以降の変更を元に戻して最後のコミットを要求する前までの変更を継続して追加したり、トランザクション全体を中止することができます。
トランザクションを開始するには、START TRANSACTION ステートメントを使用します。ROLLBACK または COMMIT WORK ステートメントを発行するまでトランザクションはアクティブです。
セーブポイントを設定するには、SAVEPOINT ステートメントを使用します。
SAVEPOINT SP1;
セーブポイントにロールバックするには、ROLLBACK TO SAVEPOINT ステートメントを使用します。
ROLLBACK TO SAVEPOINT SP1;
セーブポイント名は、現在の SQL トランザクション内の現在アクティブなセーブポイントを指定する必要があります。このセーブポイントを設定した後の変更はキャンセルされます。
セーブポイントを削除するには、RELEASE SAVEPOINT ステートメントを使用します。
RELEASE SAVEPOINT SP1;
このステートメントは SQL トランザクションがアクティブな場合のみ使用できます。
COMMIT WORK ステートメントを発行した場合、現在の SQL トランザクションによって定義されたセーブポイントはすべて破棄され、トランザクションがコミットされます。
メモ:ROLLBACK TO SAVEPOINT と ROLLBACK WORK を混同しないでください。前者は指定したセーブポイントまでの操作をキャンセルし、一方後者は最も外側のトランザクションとその中にあるセーブポイントをすべてキャンセルします。
セーブポイントはトランザクションをネストする方法を提供します。これによりアプリケーションは、一連のステートメントが正常に完了するのを待つ間、トランザクション内の前の操作を保存することができます。たとえば、この目的で WHILE ループを使用することができます。最初の試行で失敗する可能性のある一連のステートメントの開始前にセーブポイントを設定することができます。トランザクションが進行する前に、このサブトランザクションが正常に完了する必要があります。失敗した場合、サブトランザクションはセーブポイントにロールバックし、そこから再試行できます。サブトランザクションが成功した場合、トランザクションの残りの部分が続行されます。
SAVEPOINT ステートメントを発行するときは SQL トランザクションがアクティブである必要があります。
メモ:MicroKernel は各トランザクションが内部的にネストするレベルを合計 255 まで許可します。ただし、Zen は INSERT、UPDATE、DELETE ステートメントでアトミシティを保証するために内部的にこれらのレベルをいくつか使用します。したがって、1 つのセッションでは事実上 253 を越えるセーブポイントを一度にアクティブにすることはできません。トランザクション中に INSERT、UPDATE、DELETE ステートメントが含まれていると、トリガーによってこの制限はさらに厳しくなります。この制限に達した場合は、セーブポイントの数か、トランザクションに含まれるアトミック ステートメントの数を減らします。
セーブポイント内でロールバックされた操作は、外側のトランザクション(1 つまたは複数)が正常に完了してもコミットされません。ただし、セーブポイント内で完了した操作は、最も外側のトランザクションによって、物理的にデータベースにコミットされる前にコミットされます。
たとえば、サンプル データベースで、学生をいくつかのクラスに登録するトランザクションを開始するとします。最初の 2 つのクラスでは学生の登録が成功したとしても、3 つ目では、クラスが定員を満たしていたり、その学生が登録した別のクラスと競合したりするために登録が失敗する可能性があります。学生をこのクラスに登録するのに失敗したとしても、前の 2 つのクラスへの登録をやり直したいとは考えないでしょう。
次のストアド プロシージャは、まず最初にセーブポイント SP1 を設定し、次に Enrolls テーブルにレコードを追加して学生をクラスに登録します。それからクラスへの現在の登録を決定し、クラスの最大定員と比較します。比較に失敗した場合、SP1 にロールバックします。成功した場合はセーブポイント SP1 を解放します。
CREATE PROCEDURE Enroll_student( IN :student ubigint, IN :classnum integer);
BEGIN
   DECLARE :CurrentEnrollment INTEGER;
   DECLARE :MaxEnrollment INTEGER;
   SAVEPOINT SP1;
   INSERT INTO Enrolls VALUES (:student, :classnum, 0.0);
   SELECT COUNT(*) INTO :CurrentEnrollment FROM Enrolls WHERE class_id = :classnum;
   SELECT Max_size INTO :MaxEnrollment FROM Class WHERE ID = :classnum;
   IF :CurrentEnrollment >= :MaxEnrollment
   THEN
      ROLLBACK to SAVEPOINT SP1;
   ELSE
      RELEASE SAVEPOINT SP1;
   END IF;
 
END;
 
メモ:SQL レベルで操作する場合、トランザクションはインターフェイスによって異なる方法で制御されます。ODBC では、トランザク ションは SQLSetConnectOption API の SQL_AUTOCOMMIT オプショ ンを使用することにより、関連する SQLTransact API も使用して制御 されます。
これらのステートメントの構文の詳細については、『SQL Engine Reference』の各ステートメントのトピックを参照してください。
特に考慮すべき点
トランザクションは、次の操作には影響しません。
辞書定義の作成または変更を行うオペレーション。したがって、ALTER TABLE、CREATE GROUP、CREATE INDEX、CREATE PROCEDURE、CREATE TABLE、CREATE TRIGGER、および CREATE VIEW の各ステートメントの結果はロールバックできません。
辞書定義を削除するオペレーション。したがって、DROP DICTIONARY、DROP GROUP、DROP INDEX、DROP PROCEDURE、DROP TABLE、DROP TRIGGER および DROP VIEW の各ステートメントの結果はロールバックできません。
セキュリティ権の割り当てまたは削除を行うオペレーション。したがって、CREATE GROUP、DROP GROUP、GRANT(アクセス権)、GRANT CREATETAB、GRANT LOGIN、REVOKE(アクセス権)、REVOKE CREATETAB および REVOKE LOGIN の各ステートメントの結果はロールバックできません。
トランザクション内でこれらの操作のいずれかを試行し Zen がステートメントを完了した場合、結果をロールバックすることはできません。
トランザクション中に、既にあるテーブルを参照している場合、トランザクション中にそのテーブルを変更または削除することはできません。つまり、辞書定義を変更することはできません。たとえば、トランザクションを開始し、Student テーブルにレコードを挿入し、Student テーブルを変更しようとすると、ALTER ステートメントは失敗します。このトランザクションから操作をコミットし、それからテーブルを変更する必要があります。
分離レベル
同様にトランザクション中にあるほかのユーザーからトランザクションが分離する範囲を定義することにより、分離レベルはトランザクション ロック単位の適用範囲を決定します。分離レベルを使用すると、Zenは、指定した分離レベルに応じて自動的にページまたはテーブルをロックします。これらの自動ロックは、Zen が内部的に制御するものですが、暗黙ロックまたはトランザクション ロックと呼びます。アプリケーションが明示的に指定したロックは明示的ロックと呼びます。以前はレコード ロックと呼んでいました。
Zen はトランザクションのために 2 つの分離レベルを提供します。
排他(アクセスするデータ ファイル全体をロックします)。ODBC の分離レベル SQL_TXN_SERIALIZABLE に相当します。
カーソル安定性(アクセスする行またはページをロックします)。ODBC の分離レベル SQL_TXN_READ_COMMITTED に相当します。
分離レベルは、ODBC API の SQLSetConnectOption を使用して設定します。
排他的分離レベル(SQL_TXN_SERIALIZABLE)
排他的分離レベルを使用する場合、ロック単位はデータ ファイル全体です。排他トランザクション内で 1 つまたは複数のファイルにアクセスすると、ファイルは、トランザクション内のほかのユーザーが行う同様のアクセスからロックされます。このタイプのロックは、同時に同一テーブルにアクセスを試みるアプリケーションが非常に少ない場合や、トランザクションが行われている間にファイルの大部分がロックされるような場合に最も有効です。
Zen は、トランザクションが終了するとファイルのロックを解除します。排他トランザクション中にテーブルにアクセスする場合、次の状態になります。
トランザクションが終了するまで、ほかのトランザクション中のタスクは、そのテーブルに対する行の読み込み、更新、削除、挿入を行えません。
ほかのトランザクション中でないタスクは、そのテーブルの行を読むことができますが、更新、削除、挿入はできません。
同一タスク内の複数のカーソルはテーブル内のどの行も読むことができます。ただし、特定のカーソルで更新、削除、挿入操作を実行すると、Zen はそのカーソルのためにデータ ファイル全体をロックします。
排他的分離レベルを使用して結合ビューを介してテーブルにアクセスする場合、Zen はビュー内でアクセスされたすべてのファイルをロックします。
カーソル安定性分離レベル(SQL_TXN_READ_COMMITTED)
MicroKernel エンジンはデータ ファイルを一連のデータ ページとインデックス ページとして保持します。カーソル安定性分離レベルを使用する場合、ロック単位はデータ ファイルではなく、データ ページまたはインデックス ページです。カーソル安定性トランザクション内でレコードを読み込むと、Zen はこれらのレコードが含まれるデータ ページをロックし更新可能にします。しかし、複数のトランザクション中のタスクによってテーブルが並行アクセスされることは許可します。これらのレコード ロックは、ほかのレコードのセットを読み込む場合にのみ解放されます。Zen はレベル カーソル安定性をサポートします。これによりアプリケーションが同時に複数のレコードをフェッチできるためです。
さらに、データ ページまたはインデックス ページに対する変更は、次の読み込み操作を発行したとしても、トランザクションの継続中これらのレコードをロックします。操作をコミットまたはロールバックするまで、トランザクション中のほかのユーザーはこれらのロックされたレコードにアクセスすることはできません。ただし、ほかのアプリケーションは、それぞれのトランザクション内から、同一ファイルの別のページをロックすることはできます。
カーソル安定性トランザクション中にファイルにアクセスする場合、Zen はデータ ページおよびインデックス ページを次のようにロックします。
行を読むことはできますが、更新したり削除したりすることはできません。Zen は、次の行読み込み操作が行われるか、トランザクションを終了するまで、その行のあるデータ ページをロックします。
行内のインデックスでない列の更新、インデックスを含まない行のテーブルからの削除、インデックスを含まない新しい行のテーブルへの挿入を行うことができます。Zen は、それに続く読み込み操作にかかわらず、残りのトランザクションの間中、その行のあるデータ ページをロックします。
行内のインデックス列の更新、インデックスを含む行のテーブルからの削除、インデックスを含む新しい行のテーブルへの挿入を行うことができます。Zen は、それに続く読み込み操作にかかわらず、残りのトランザクションの間中、影響を受けるインデックス ページをデータ ページと同様ロックします。
カーソル安定性は、ほかのユーザーが同一データ ファイルのほかのデータ ページにアクセスすることを許可しながら、読み込んだデータを確実に安定した状態に保つことができます。カーソル安定性分離レベルでは、一度に読み込める行の数を制限することにより、一度にロックされるデータ ページ数が少なくなり、一般的にすべてのタスクでより優れた並行性を実現できます。これにより、ロックするページが少ないため、ほかのネットワーク ユーザーは、データ ファイルのより多くのページにアクセスできます。
ただし、アプリケーションが多数の行をスキャンまたは更新する場合、影響するテーブルからほかのユーザーを完全にロックする可能性が高くなります。したがって、小さなトランザクションで読み込み、書き込み、コミットを行う場合にカーソル安定性を使用するのが最も良い方法です。
カーソル安定性はサブクエリ内のレコードをロックしません。カーソル安定性は、行が返された状態が変更されないことを保証するのではなく、実際に返された行が変更されないことを保証します。
トランザクションと分離レベル
トランザクション内でデータにアクセスする場合はいつでも、Zen はアクセスされたページまたはファイルをそのアプリケーションのためにロックします。ほかのアプリケーションは、ロックが解除されるまで、ロックされたページまたはファイルに書き込むことはできません。
カーソル安定性分離レベルを使用すると、結合ビューでテーブルにアクセスする場合、Zen はビュー内のすべてのテーブルのアクセスされたページをロックします。カーソル安定性分離レベルを使用すると、結合ビューでテーブルにアクセスする場合、Zen はビュー内のすべてのテーブルのアクセスされたページをロックします。
Zen はノーウェイト トランザクションを実行します。別のタスクがロックしているレコードに、トランザクション内からアクセスした場合、Zen はページまたはテーブルがロックされているか、デッドロックが検出されたことを知らせます。いずれの場合にも、トランザクションをロールバックし、再試行してください。Zen では、同一のアプリケーション内から同一のデータ ファイルにアクセスする複数のカーソルを使用できます。
次の手順は、2 つのアプリケーションがトランザクション内から同一テーブルにアクセスする場合にどのように相互作用するかを示しています。手順には番号が付けられていて、発生した順を示します。
タスク 1     
タスク 2
1. ビューをアクティブにします。
 
 
2. ビューをアクティブにします。
3. トランザクションを開始します。
 
 
4. トランザクションを開始します。
5. レコードをフェッチします。
 
 
6. 同一データ ファイルからレコードのフェッチを試行します。
 
7. 両方のタスクがカーソル安定性を使用していて、タスク 2 が、既にタスク 1 がロックしているのと同じレコードをフェッチしようとすると、ステータス コード 84(レコードまたはページがロックされている)を受け取ります。どちらか一方のタスクが排他トランザクションを使用している場合は、ステータスコード 85(ファイルがロックされている)を受け取ります。
 
8. 必要に応じフェッチを再試行します。
9. レコードを更新します。
 
10. トランザクションを終了します。
 
 
11. フェッチに成功します。
 
12. レコードを更新します。
 
13. トランザクションを終了します。
トランザクションは、ほかのアプリケーションによる更新に対し、一時的にレコード、ページ、またはテーブルをロックするため、アプリケーションはトランザクション中にオペレーター入力のための中断を行ってはいけません。これは、オペレーターが応答するかトランザクションが終了されるまで、トランザクションからアクセスされているレコード、ページまたはテーブルを、ほかのどのアプリケーションも更新できないためです。
メモ:カーソル安定性トランザクション内でのレコードの読み込みは、それに続く更新処理が競合なしに成功することを保証するものではありません。これは、Zen が更新を完了するのに必要とするインデックス ページを、ほかのアプリケーションが既にロックしていることがあるためです。
デッドロックの回避
デッドロック状態は、2 つのアプリケーションが、一方が既にロックしたテーブル、データ ページ、インデックス ページ、またはレコードに対し操作を再試行する場合に発生します。デッドロックの発生を最小限に抑えるには、アプリケーションでトランザクションのコミットを頻繁に行います。アプリケーションから操作の再試行を行わないでください。Zen はエラーを返す前に妥当な回数の再試行を行います。
排他的分離レベル下のデッドロック状態
排他的分離レベルを使用する場合、Zen は、データ ファイル全体をほかのアプリケーションの更新からロックします。したがって、アプリケーションが同じ順序でデータ ファイルにアクセスしない場合、次の表のようにデッドロックが起こる可能性があります。
タスク 1
タスク 2
1. トランザクションを開始します。
 
 
2. トランザクションを開始します。
3. ファイル 1 からフェッチします。
 
 
4. ファイル 2 からフェッチします。
5. ファイル 2 からフェッチします。
 
6. ロックのステータス コードを受け取ります。
 
7. 手順 5 を再試行します。
 
 
8. ファイル 1 からフェッチします。
 
9. ロックのステータス コードを受け取ります。
 
10. 手順 8 を再試行します。
カーソル安定性分離レベル下のデッドロック状態
カーソル安定性分離レベルを使用する場合、アプリケーションがアクセスしているファイルのレコードまたはページ(アプリケーションがロックしていないレコードまたはページ)を、ほかのアプリケーションが読み込み、更新することができます。
パッシブ コントロール
アプリケーションが単一レコードのフェッチを行い、論理的に関連しない一連の更新処理を行う場合、Zen の並行制御であるパッシブ メソッドを使用することができます。この方法を使用すると、トランザクションやレコード ロックを行わずに、レコードをフェッチ、更新、または削除することができます。これらの操作は楽観的更新および削除と呼ばれます。
タスクがトランザクションも明示的レコード ロックも使用しないで更新および削除操作を行う場合、デフォルトで、そのタスクはほかのタスクの変更を上書きできません。このデータの整合性を確実にするこの機能は、パッシブ コントロールで、楽観的並行制御と呼ばれることもあります。パッシブ コントロールでは、タスクはどのような種類のロックも行いません。既にフェッチしてあるレコードを別のタスクが変更した場合、更新または削除オペレーションを実行する前に、そのレコードを再度フェッチする必要があります。
パッシブ コントロールの下では、レコードをフェッチしてから更新または削除操作をする間に別のアプリケーションがそのレコードを更新または削除した場合、競合のステータス コードが返されます。これは、最初にデータをフェッチしてから、別のアプリケーションがそのデータに変更を加えたことを示します。競合のステータス コードを受け取った場合、更新または削除操作を実行する前にもう一度そのレコードをフェッチする必要があります。
パッシブ コントロールを使用すると、シングル ユーザー システムで設計されたアプリケーションを、ロック呼び出しを実装することなくネットワーク上で実行することができます。ただし、パッシブ コントロールは、負荷の軽いネットワーク環境で使用されるか、データがほとんど変化しないような場合にのみ有効です。負荷の高いネットワーク環境や変化の激しいデータの場合、パッシブ コントロールは有効ではありません。
Zen データベースのアトミシティ
アトミシティの原則は、所定のステートメントの実行が完了しなかった場合、データベースに部分的またはあいまいな影響を残してはいけない、ということです。たとえば、あるステートメントが 5 レコードの内 3 レコードを挿入したあとに失敗して、その 3 レコードを元に戻さなかった場合、操作を再試行するときにデータベースの一貫性は失われています。ステートメントがアトミックで実行の完了に失敗した場合、すべての変更はロールバックされ、データベースの一貫性は保たれます。この例では、5 レコードの挿入で 1 つでも失敗した場合は、1 つのレコードも挿入されてはいけません。
アトミシティの規則は、複数のレコードまたはテーブルを変更するステートメントで特に重要です。また、アトミシティの規則は、失敗した操作の再試行をより簡単にします。前の試行による部分的な影響も残っていないことが保証されるからです。
Zen は 2 つの方法でアトミシティを実施します。
1 UPDATE、INSERT、DELETE ステートメントはアトミックと定義されています。Zen は複数のレコードまたは複数のテーブルの変更操作が失敗した場合、変更の影響がデータベースにまったく残らないことを保証します。
プロシージャの内部または外部のいずれで実行されたかにかかわらず、更新、挿入、削除操作でアトミシティは保証されます。
2 ストアド プロシージャを作成する際、ATOMIC として指定することができます。このようなプロシージャは、その実行全体にアトミシティの規則を適用します。したがって、ATOMIC プロシージャ内の UPDATE、INSERT、DELETE ステートメントがアトミックに実行されるだけでなく、そのプロシージャ内のほかのどのステートメントが失敗した場合でも、そのプロシージャの実行による影響はロールバックされます。
プロシージャ内のトランザクション制御
トリガーは常に外部のデータ変更ステートメント(INSERT、DELETE、または UPDATE)によって開始され、すべてのデータ変更ステートメントはアトミックであるため、次のステートメントは、トリガー内またはトリガーによって起動されるプロシージャ内では使用できません。
START TRANSACTION
COMMIT WORK
ROLLBACK WORK(RELEASE SAVEPOINT および ROLLBACK TO SAVEPOINT を含む)
言い換えると、トリガーは ATOMIC 複合ステートメントと同じ規則に従います。
ユーザーが起動した COMMIT WORK、ROLLBACK WORK、RELEASE SAVEPOINT、ROLLBACK TO SAVEPOINT ステートメントは、(アトミシティの目的で)システムが開始したトランザクションを終了させることはありません。