02июн
Большие объекты в СУРБД ORACLE. BLOB, CLOB
BLOB, CLOB – это внутренние большие объекты. Основные правила работы с этими объектами:
- В основу работы с этими объектами положена транзакция, то есть любое изменение может быть зафиксировано или отменено.
- Фактическое значение столбца LOB может храниться как часть строки таблицы, либо отдельно. Если длина столбца LOB больше 4000 байт, значение автоматически переносится в другое место.
- Есть три состояния большого объекта: может быть пустым, может иметь значение null, может иметь какое-то конкретное значение. NULL – нет ни локатора ни значения у объекта. Пустой объект – имеется локатор, но он указывает на пустое место в базе данных.
- Переменные и атрибуты объекта LOB могут играть роль промежуточного хранилища для локаторов LOB, указывающих на реальное значение в базе данных. То есть только столбец таблицы может содержать значение объекта LOB. Переменная Lob не представляет никакого фактического значения. Переменная содержит только локатор, соответствующий столбцу lob в базе данных.
- У каждого LOB–столбца есть отдельный локатор и отдельное значение. То есть, если вы lob–столбцу присваиваете значение другого Lob-столбца, то этот столбец получает новое значение и новый локатор.
- Непротиворечивость чтения внутренних больших объектов обеспечивается с помощью собственных механизмов многовариантности.
Давайте посмотрим на некоторые примеры.
Предположим, мы имеем табличку
CREATE TABLE DEMO (ID INTEGER, THEBLOB BLOB)
Для инициализации больших объектов существуют следующие встроенные функции:
function EMPTY_CLOB return clob;
function EMPTY_BLOB return blob;
Эти функции создают пустой локатор.
insert into demo values (1,empty_blob()));
Сделаем выборку
declare
the_id integer;
the_blob blob;
begin
SELECT ID, THEBLOB into the_id, the_blob FROM DEMO where rownum=1;
end;
Так вот - в этом примере переменная the_blob получает локатор из столбца типа blob. Самого значения эта переменная не содержит, а содержит только указатель на местонахождение этого значения в базе данных.
А в следующем примере мы вставим новую строку в таблицу
declare
the_id integer;
the_blob blob;
begin
SELECT ID, THEBLOB into the_id,the_blob FROM DEMO where rownum=1;
insert into demo values (2,the_blob);
end;
Теперь две строки имеют идентичное содержимое поля theblob, значения хранятся в разных местах, на которые указывают их отдельные локаторы.
Работа с внутренними большим объектами похожа на работу с другими типами данных, но подход ORACLE совершенно другой: доступ к ним реализуется через локаторы. Поэтому возникают некоторые проблемы в вопросе непротиворечивости чтения больших объектов.
Когда столбец внутреннего большого объекта меняет своё значение, предыдущее его значение не сохраняется в сегменте отката, как это происходит для других типов данных. Происходит все иначе: в пространстве, которое выделено для lob появляются дополнительные страницы, на которых и сохраняются предыдущие значения lob. Вывод: непротиворечивость чтения внутренних больших объектов достигается посредством их собственных механизмов многовариантности.
Обращаю ваше внимание, что все манипуляции с внутренними большими объектами производятся на основе транзакции. Когда транзакция, в которой прошла модификация Lob, зафиксирована, то дальнейшее использование соответствующего локатора становится некорректным. Локатор необходимо выбрать снова.
Давайте, углубимся в детали и посмотрим пример.
Когда локатор большого объекта выбрать в переменную lob, то это локатор становится согласованным по чтению. То есть, значение lob будет всегда таким, каким оно было на момент выбора локатора. Другими словами, когда локатор lob помещается в переменную, он получает СОБСТВЕННОЕ ПРЕДСТАВЛЕНИЕ значения lob.
В pl/sql возможны два способа обновления столбца внутреннего большого объекта: оператором update и пакетом dbms_lob. При использовании пакета dbms_lob, обновляемый локатор позволяет видеть результаты обновления. Чего нельзя сказать об операторе update. Чтобы увидеть новое значение, нужно по-новому выбрать обновленный столбец или использовать update с предложением returning .
А теперь пример с комментариями:
SQL> declare
2 the_id integer;
3 the_blob1 blob;
4 the_blob2 blob;
5 begin
6 -- выбираем локатор согласованный по чтению
7 SELECT ID, THEBLOB into the_id,the_blob1 FROM DEMO where id=1;
8 -- создадим еще один новый локатор согласованный по чтению
9 the_blob2:=the_blob1;
10 -- после следующего оператора записи с id=1 и id=21 будут иметь одинаковое значение столбца blob.
11 update demo set theblob=the_blob2 where id=21;
12 --после следующего оператора запись с id=1 буде иметь локатор чистый для столбца lob
13 update demo set theblob=empty_blob() where id=1;
14 -- но мы еще можем видеть старое значение этого столбца. Поэтому создадим новую запись с эти значением
15 insert into demo values ( 33,the_blob1) returning theblob into the_blob2;
16 -- после этого оператора получем согласованный по чтению локатор в the_blob2
17
18 delete FROM DEMO where id=1;
19 --удаляем запись с id=1, но все равно мы ещё можем получить значение столбца lob
20 insert into demo values ( 44,the_blob1);
21 commit;
22 end;
23 /
PL/SQL procedure successfully completed.
В этом примере наглядно показано, что при манипуляциях с большими внутренними объектами не следует читать или записывать их непосредственно, все манипуляции нужно реализовывать через локаторы.
Работать с внешними большими объектами можно с помощью пакета dbms_lob (см. нашу соответствующую статью).