Двухфазная фиксация / общая транзакция - PullRequest
4 голосов
/ 18 сентября 2008

Сценарий такой

У нас есть два приложения A и B, оба выполняются в отдельных транзакциях базы данных (Oracle 9i)

Приложение A - вставляет некоторые данные в базу данных, затем вызывает приложение B Приложение B - вставляет некоторые данные в базу данных, связанные (через внешние ключи) с данными А. Возвращает «ID» в Приложение A Приложение A - использует идентификатор для вставки дополнительных данных, включая идентификатор из B

Теперь, поскольку это отдельные транзакции, но обе основаны на данных от транзакций друг друга, нам нужно фиксировать между вызовами к каждому приложению. Это, конечно, очень затрудняет откат, если что-то пойдет не так.

Как бы вы подошли к этой проблеме, с минимальным рефакторингом кода. Конечно, такого рода это распространенная проблема в мире SOA?

------ Обновление --------

Мне не удалось найти что-либо в Oracle 9i, однако Oracle 11g предоставляет DBMS_XA , что делает именно то, что я делал.

Ответы [ 5 ]

11 голосов
/ 18 сентября 2008

У вас есть три варианта:

  1. Перепроектируйте приложение, чтобы у вас не было двух разных процессов (оба с подключениями к базе данных), записывающих в базу данных и сверните их в одно приложение.

  2. Создание приложения C, которое обрабатывает все транзакции базы данных для A и B.

  3. Бросьте свой собственный двухфазный коммит. Приложение C действует как координатор. C сигналы A и B, чтобы спросить, готовы ли они совершить. A и B выполняют свою обработку и отвечают на C ответом «готово» или «отказано» (обратите внимание, что на C должен быть тайм-аут, чтобы избежать бесконечного ожидания, если один процесс зависает или умирает). Если оба ответа готовы, C говорит им о коммите. В противном случае он отправляет сигнал отката.

Обратите внимание, что у вас могут возникнуть проблемы с вариантом 3, если приложение A использует внешние ключи из приложения B (о чем вы не заявили, так что это может не быть проблемой). Согласованность чтения Oracle, вероятно, помешает этому разрешить, поскольку транзакция приложения A начнется раньше, чем приложение B. Просто предупреждение.

3 голосов
/ 18 сентября 2008

Несколько предложений:

  • Использование Компенсирующие транзакции . По сути, вы позволяете отменить транзакцию, которую вы сделали ранее. Сложнее всего выяснить, какие транзакции нужно откатить.

  • Зафиксируйте данные приложений A и B в базе данных, используя флаг, указывающий, что это только временно. Затем, после того, как все в порядке, измените флаг, чтобы указать, что данные являются окончательными. Ночью запустите пакетное задание, чтобы очистить данные, которые еще не были завершены.

2 голосов
/ 18 сентября 2008

Вероятно, вы могли бы вставить данные из приложения A во «временную» область, чтобы приложение B могло выполнять вставку как A, так и B без значительных изменений в обоих приложениях. Это не особенно элегантно, но может помочь.

В другом сценарии вы можете добавить поле «Подтверждение» к вашим данным, которое обновляется после успешного выполнения всего процесса. Если в какой-то момент произойдет сбой, может быть проще отследить записи, которые необходимо откатить (фактически удалить).

1 голос
/ 18 сентября 2008

Мне нравятся оба представленных решения, поэтому я некоторое время избегал публиковать их. Но вы также можете обновить основную таблицу, предварительно сохранив состояние затронутых строк в некотором кеше.

Это может быть объединено с двухуровневым (система гаишников, предложенная Затрусом) - потому что она действительно не понадобится для решения Neonski использования таблицы или таблиц "sketchpad". Недостаток этого заключается в том, что вам нужно, чтобы ваши прокси / логика обращались к основной таблице из рабочей области или из рабочей области из основной таблицы - или, возможно, сохраняли свой флаг в основной таблице и устанавливали его обратно, когда вы фиксируете данные в основной стол.

Леди из нашей команды разрабатывает нечто подобное для нашей системы реального времени, используя постоянные рабочие столы.

0 голосов
/ 18 сентября 2008
App_A =={0}=>               database # App_A stores information for App_B
App_A ------> App_B                  # App_A starts App_B
              App_B <={0}== database # App_B retrieves the information
              App_B =={1}=> database # App_B stores more informaion
App_A <={2}== App_B                  # App_B returns 'ID' to App_A
App_A ={2,3}>               database # App_A stores 'ID' and additional data

Это только я или кажется, что приложение B - это просто подпрограмма A. Я имею в виду, что приложение B ничего не делает, пока A не спросит об этом, а приложение A ничего не сделает, пока B не вернет ID. Это означает, что не имеет смысла иметь их в разных приложениях или даже в отдельных потоках.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...