Одним из действительно замечательных свойств СУБД Oracle является ее способность прозрачно обрабатывать распределенные транзакции. Я могу обновить данные во множестве разных баз данных за одну транзакцию. Когда я выполняю ее фиксацию, то либо фиксируются все обновления во всех экземплярах, либо не фиксируется ни одно из них (все они откатываются). Мне не нужен для этого никакой дополнительный код; я просто пишу commit;.
Ключом к распределенным транзакциям в Oracle является связь баз данных (database link). Эта связь представляет собой объект базы данных, описывающий способ регистрации в другом экземпляре базы из вашего экземпляра. Однако цель настоящего раздела не в том, чтобы раскрыть синтаксис команд связи баз данных (он полностью документирован), а скорее просто в том, чтобы уведомить вас о его существовании. Как только вы настроите связь баз данных, доступ к удаленным объектам становится очень простым:
select * from T@another_database;
Это позволит выбрать данные из таблицы T в экземпляре базы данных, определенном связью ANOTHER_DATABASE. Обычно вы должны “скрывать” тот факт, что T— удаленная таблица, создавая ее представление или синоним. Например, можно выполнить следующую команду и затем обращаться к T, как если бы это была локальная таблица:
create synonym T for T@another_database;
Теперь, имея настроенную связь с удаленной базой и получив возможность читать некоторые таблицы, я также могу модифицировать их (конечно, при условии обладания соответствующими привилегиями). Выполнение распределенной транзакции теперь ничем не отличается от транзакции локальной. Вот все, что для этого нужно:
update local_table set x = 5;
update remote_table@another_database set y = 10;
commit;
Вот и все. СУБД Oracle выполнит фиксацию либо в обеих базах данных, либо ни в одной из них. Она использует протокол 2PC (двухфазной фиксации). Этот протокол позволяет выполнять модификации, затрагивающие множество различных баз данных, фиксируя их автоматически. Он, насколько возможно, пытается перекрыть все пути для распределенных сбоев перед тем, как выполнить фиксацию. В 2PC между многими базами данных одна из баз — обычно та, к которой клиент подключился изначально — служит координатором распределенной транзакции. Этот сайт запросит у других сайтов готовности к фиксации. То есть этот сайт обратится к другим сайтам и попросит их подготовиться к фиксации. Каждый из этих других сайтов рапортует о своем “состоянии готовности”, как “ДА” или “НЕТ”. Если любой из сайтов говорит “НЕТ”, выполняется откат всей транзакции. Если же все сайты рапортуют “ДА”, сайт-координатор рассылает сообщение с командой на выполнение фиксации на всех сайтах.
Это ограничивает возможности для серьезных ошибок. Прежде чем выполнится “опрос” по 2PC, любая распределенная ошибка приведет к выполнению отката на всех сайтах. Не будет никаких сомнений относительно исхода распределенной транзакции. После команды на фиксацию или откат опять-таки нет никаких сомнений относительно исхода распределенной транзакции. Лишь в течение очень короткого периода (“окна”) времени, когда координатор собирает ответы, исход может быть неоднозначным после сбоя.
Предположим, например, что у нас есть три сайта, участвующих в транзакции. Сайт 1 выступает в роли координатора. Сайт 1 просит сайт 2 подготовиться к фиксации, и сайт 2 выполняет это. Затем сайт 1 просить сайт 3 подготовиться к фиксации, и он также делает это. В этот момент времени сайт 1 — единственный, кто знает об исходе транзакции, и теперь он отвечает за извещение об этом других сайтов. Если ошибка случится прямо сейчас — произойдет сбой сети, сайт 1 останется без питания или еще что-то — сайты 2 и 3 останутся в “подвешенном” состоянии. Они получат то, что называется сомнительной распределенной транзакцией. Протокол 2PC пытается закрыть “окно” ошибок, насколько это возможно, но не может исключить такую вероятность полностью. Сайты 2 и 3 должны удерживать транзакцию открытой, ожидая нотификации от сайта 1 команды на фиксацию или откат. Если вы помните дискуссию об архитектуре из главы 5, там было сказано,
что для разрешения этой проблемы существует процесс RECO. Это также тот случай, когда на сцену выходят COMMIT и ROLLBACK с опцией FORCE. Если причиной проблемы был сбой сети между сайтами 1, 2 и 3, то администраторы сайтов 2 и 3 должны обратиться к администратору сайта 1, запросить его об исходе транзакции и выполнить, соответственно, фиксацию или откат вручную. Существует несколько (немного) ограничений относительно того, что вы можете делать в распределенной транзакции, и все они оправданы (на мой взгляд, они выглядят оправданными в любом случае). Ниже перечислены наиболее существенные из них.
Вы не можете выдать COMMIT по связи баз данных. То есть, нельзя дать команду COMMIT@удаленный_сайт. Вы можете зафиксировать транзакцию только на сайте, который ее инициировал.
Вы не можете выполнять DDL в удаленной базе по связи баз данных. Это — прямое следствие предыдущего ограничения. DDL выполняет фиксацию. Нельзя выполнить фиксацию ни с одного сайта, кроме инициирующего, а потому нельзя выполнять DDL по связи баз данных.
Нельзя выдать SAVEPOINT по связи баз данных. Короче говоря, вы не можете выдать ни одного оператора управления транзакциями по связи баз данных. Все управление транзакциями наследуется от сеанса, который первоначально открывает связи баз данных. Вы не можете осуществлять другого управления транзакциями на распределенных экземплярах в транзакции.
Недостаток управления транзакциями по связи баз данных также оправдан, поскольку инициирующий сайт — единственный, имеющий список всех, кто вовлечен в транзакцию. Если в нашей конфигурации из трех сайтов сайт 2 попытается зафиксировать транзакцию, у него не будет никаких сведений о том, что в ней участвует сайт 3. Поэтому в Oracle только сайт 1 может выдать команду на фиксацию. В этой точке для сайта 1 допустимо делегировать ответственность за управление распределенной транзакцией другому сайту.
Мы можем указать, какой сайт будет действительным фиксирующим сайтом, устанавливая параметр COMMIT_POINT_STRENGTH (“сила точки фиксации”) сайта. Сила точки фиксации ассоциирует относительный уровень важности с сервером в распределенной транзакции. Чем более важен сервер (больше доступных данных должно быть на нем), тем более вероятно, что именно он будет координировать распределенную транзакцию. Вам может понадобиться это в случае, когда необходимо выполнить распределенную транзакцию между вашим рабочим сервером и тестовым сервером. Поскольку координатор транзакции никогда не сомневается в исходе транзакции, будет лучше, если рабочий сервер станет координировать распределенную транзакцию. Вам не нужно особо беспокоиться о вашем тестовом сервере — что на нем вдруг окажутся открытые транзакции или блокированные ресурсы. Вам определенно стоит беспокоиться, если подобное случится на рабочем сервере.
В невозможности выполнения DDL по связи баз данных вообще нет ничего плохого. Во-первых, DDL случается редко. Вы выполняете операторы DDL при инсталляции или обновлении. Рабочие системы не выполняют DDL (по крайней мере, не должны). Во-вторых, все-таки существует способ запустить DDL через связь баз данных — воспользоваться средством планирования заданий DBMS_JOB или, в
Oracle 10g — пакетом планировщика DBMS_SCHEDULER. Вместо того чтобы пытаться выполнить DDL по связи, вы используете связь для планирования удаленного задания, чтобы оно выполнилось, как только вы осуществите фиксацию. Таким образом, задание запустится на удаленной машине, оно не будет частью распределенной транзакции и потому сможет выполнить операторы DDL. Фактически это метод, посредством которого сервер репликации Oracle (Oracle Replication Server) выполняет распределенные команды DDL, чтобы осуществить репликацию схемы.
< Предыдущая | Следующая > |
---|