13.2 LOBロケータとトランザクション境界
LOBロケータは、トランザクションとトランザクションIDの両方で使用できます。
- LOBロケータとトランザクション境界について
この項では、LOBロケータとトランザクション境界について説明します。 - ロケータを使用したLOBに対する読取りおよび書込み
操作ロケータにトランザクションIDが含まれているかどうかにかかわらず、常にロケータを使用してLOBデータを読み取ることができます。この項では、その様々な側面について学習します。 - トランザクション境界外でのロケータの選択
この項では、トランザクション外でロケータが選択された場合に、シリアライズ可能でないトランザクションでロケータを使用する方法を説明する2つの使用例を示します。 - トランザクション境界内でのロケータの選択
この項では、トランザクション内でロケータが選択された場合に、シリアライズ可能でないトランザクションでロケータを使用する方法を説明する2つの使用例を示します。 - 複数のトランザクションにまたがることはできないLOBロケータ
データの書込みに使用されるLOBロケータは、複数のトランザクションにまたがることはできません。ただし、シリアライズ可能なトランザクション内でない場合は、ロケータを使用してLOB値を読み取ることができます。 - トランザクションにまたがらないロケータの例
トランザクションにまたがらないロケータの例では、print_media
表を使用します。
関連項目:
LOBロケータの詳細は、LOB用のロケータ・インタフェースを参照してください親トピック: 高度な設計時の考慮事項
13.2.1 LOBロケータとトランザクション境界について
この項では、LOBロケータとトランザクション境界について学習します。
LOBロケータとトランザクションについては、次のことに注意してください。
-
トランザクションを開始してからロケータを選択する場合: トランザクションを開始した後にロケータを選択すると、ロケータにトランザクションIDが含まれます。トランザクションを明示的に開始しなくてもトランザクションに暗黙的に入ることができます。たとえば、
SELECT
...FOR
UPDATE
によってトランザクションは暗黙的に開始されます。このような場合、ロケータにはトランザクションIDが含まれます。 -
ロケータがトランザクションIDを含まない場合
-
トランザクション外でロケータを選択する場合: 対照的に、トランザクションの外部でロケータを選択する場合、ロケータはトランザクションIDを含みません。
-
DML文の実行の前に選択した場合: トランザクションIDは、最初のDML文が実行されるまでは割り当てられません。このため、このようなDML文の前に選択されたロケータはIDを含みません。
-
親トピック: LOBロケータとトランザクション境界
13.2.2 ロケータを使用したLOBに対する読取りおよび書込み操作
ロケータがトランザクションIDを含んでいるかどうかにかかわらず、常にロケータを使用してLOBデータを読み取ることができます。この項では、その様々な側面について学習します。
-
ロケータを使用して書込みができない場合:
ロケータがトランザクションIDを含む場合、その特定のトランザクション外でLOBに書き込むことはできません。
-
ロケータを使用して書込みができる場合:
ロケータがトランザクションIDを含まない場合、トランザクションを明示的または暗黙的に開始した後、LOBに書き込むことができます。
-
シリアライズ可能なトランザクションでロケータを使用して読取りまたは書込みができない場合:
ロケータが古いトランザクションのトランザクションIDを含み、現在のトランザクションがシリアライズ可能である場合、このロケータを使用して読取りまたは書込みを行うことはできません。
-
シリアライズ不能なトランザクションでロケータを使用して読取りはできるが書込みができない場合:
トランザクションがシリアライズ不能である場合、トランザクション外で読み取ることはできますが、書き込むことはできません。
「トランザクション境界外でのロケータの選択」、「トランザクション境界内でのロケータの選択」、「複数のトランザクションにまたがることはできないLOBロケータ」および「トランザクションにまたがらないロケータの例」の各例は、ロケータとシリアライズ可能でないトランザクション間の関係を示しています
親トピック: LOBロケータとトランザクション境界
13.2.3 トランザクション境界外でのロケータの選択
この項では、トランザクション外でロケータが選択された場合に、シリアライズ可能でないトランザクションでロケータを使用する方法を説明する2つの使用例を示します。
シナリオ1:
-
現行トランザクションを持たないロケータを選択します。この時点ではロケータはトランザクションIDを含みません。
-
トランザクションを開始します。
-
ロケータを使用してLOBからデータを読み取ります。
-
トランザクションをコミットまたはロールバックします。
-
ロケータを使用してLOBからデータを読み取ります。
-
トランザクションを開始します。ロケータはトランザクションIDを含みません。
-
ロケータを使用してデータをLOBに書き込みます。この操作は、ロケータが書込みの前にトランザクションIDを含まないため有効です。このコールの後、ロケータはトランザクションIDを含むようになります。
シナリオ2:
- 現行トランザクションを持たないロケータを選択します。この時点ではロケータはトランザクションIDを含みません。
- トランザクションを開始します。ロケータはトランザクションIDを含みません。
- ロケータを使用してLOBからデータを読み取ります。ロケータはトランザクションIDを含みません。
- ロケータを使用してデータをLOBに書き込みます。この操作は、ロケータが書込みの前にトランザクションIDを含まないため有効です。このコールの後、ロケータはトランザクションIDを含むようになります。続けてLOBの読取りまたは書込みを行うことができます。
- トランザクションをコミットまたはロールバックします。ロケータは引き続きトランザクションIDを含みます。
- ロケータを使用してLOBからデータを読み取ります。この操作は有効です。
- トランザクションを開始します。ロケータは前のトランザクションのIDを含んでいます。
- ロケータを使用してデータをLOBに書き込みます。ロケータが現行トランザクションに一致するトランザクションIDを含まないため、この書込み操作は失敗します。
親トピック: LOBロケータとトランザクション境界
13.2.4 トランザクション境界内でのロケータの選択
この項では、トランザクション内でロケータが選択された場合に、シリアライズ可能でないトランザクションでロケータを使用する方法を説明する2つの使用例を示します。
シナリオ1:
-
トランザクションの中でロケータを選択します。この時点では、ロケータはトランザクションIDを含んでいます。
-
トランザクションを開始します。ロケータは前のトランザクションのIDを含んでいます。
-
ロケータを使用してLOBからデータを読み取ります。ロケータの中のトランザクションIDは現在のトランザクションに一致していませんが、この操作は有効です。
関連項目:
ロケータを使用したLOBデータの読取りの詳細は、「読取り一貫性のあるロケータ」を参照してください。
-
ロケータを使用してデータをLOBに書き込みます。ロケータの中のトランザクションIDが現在のトランザクションに一致していないため、この操作は失敗します。
シナリオ2:
- トランザクションを開始します。
- ロケータを選択します。ロケータがトランザクションの中で選択されたため、トランザクションIDが含まれています。
- ロケータを使用してLOBの読取りまたは書込みを行います。これらの操作は有効です。
- トランザクションをコミットまたはロールバックします。ロケータは引き続きトランザクションIDを含みます。
- ロケータを使用してLOBからデータを読み取ります。ロケータの中にトランザクションIDがあり、そのトランザクションはすでにコミットまたはロールバックされていますが、この操作は有効です。
- ロケータを使用してデータをLOBに書き込みます。ロケータの中のトランザクションIDはすでにコミットまたはロールバックされたトランザクション用であるため、この操作は失敗します。
親トピック: LOBロケータとトランザクション境界
13.2.5 複数のトランザクションにまたがることはできないLOBロケータ
データの書込みに使用するLOBロケータは、複数のトランザクションにまたがることはできません。ただし、シリアライズ可能なトランザクション内でない場合は、ロケータを使用してLOB値を読み取ることができます。
DBMS_LOB
、OCI、SQLのINSERT
文またはUPDATE
文を使用し、LOBロケータによって永続LOBの値を更新すると、読取り一貫性のあるロケータが更新済ロケータに変更されます。
INSERT
文やUPDATE
文によって、トランザクションが自動的に開始され、行がロックされます。一度これが発生すると、ロケータを現行トランザクション以外で使用して、LOB値を変更できなくなる可能性があります。データの書込みに使用するLOBロケータを複数のトランザクションにまたがって使用することはできません。ただし、シリアライズ可能なトランザクション内でない場合は、ロケータを使用してLOB値を読み取ることができます。
次のコード例では、clob_updated
というCLOB
ロケータが作成され、次の操作が実行されます。
-
最初の
SELECT
INTO
の実行時(t1)に、ad_sourcetext
内の値がロケータclob_updated
に対応付けられます。 -
次の操作で(t2)、
DBMS_LOB
.WRITE
ファンクションを使用してclob_updated
内の値を変更します。DBMS_LOB
.READ
が新しい値を示します。 -
COMMIT
文(t3)によって現行のトランザクションが終了します。 -
トランザクションを終了すると(t4)、
clob_updated
ロケータは別のトランザクション(コミット済)を参照することになるため、その後のDBMS_LOB
.WRITE
操作は失敗します。これは、戻されるエラーによって通知されます。このLOBロケータをさらにDBMS_LOB
(およびOCI)の変更操作で使用するには、再選択する必要があります。
親トピック: LOBロケータとトランザクション境界
13.2.6 トランザクションにまたがらないロケータの例
トランザクションにまたがらないロケータの例では、print_media
表を使用します。
INSERT INTO PRINT_MEDIA VALUES (2056, 20010, EMPTY_BLOB(), 'abcd', EMPTY_CLOB(), EMPTY_CLOB(), NULL, NULL, NULL, NULL); COMMIT; DECLARE num_var INTEGER; clob_updated CLOB; read_amount INTEGER; read_offset INTEGER; write_amount INTEGER; write_offset INTEGER; buffer VARCHAR2(20); BEGIN -- At time t1: SELECT ad_sourcetext INTO clob_updated FROM PRINT_MEDIA WHERE ad_id = 20010 FOR UPDATE; read_amount := 10; read_offset := 1; dbms_lob.read(clob_updated, read_amount, read_offset, buffer); dbms_output.put_line('clob_updated value: ' || buffer); -- This produces the output 'abcd' -- At time t2: write_amount := 3; write_offset := 5; buffer := 'efg'; dbms_lob.write(clob_updated, write_amount, write_offset, buffer); read_amount := 10; dbms_lob.read(clob_updated, read_amount, read_offset, buffer); dbms_output.put_line('clob_updated value: ' || buffer); -- This produces the output 'abcdefg' -- At time t3: COMMIT; -- At time t4: dbms_lob.write(clob_updated , write_amount, write_offset, buffer); -- ERROR: ORA-22990: LOB locators cannot span transactions END; /
親トピック: LOBロケータとトランザクション境界