Xpoint
   [напомнить пароль]

Distributed transaction в ява приложении

2002-10-11 13:05:41 [обр] Виктор Сорока [досье]

Есть большой проект: J2EE (WebSphere)
и есть что-то вроде сервис взаимодействия с хранилищем (CMP, BMP - не удовлетворяют)
и появилось требования иметь возможность запускать этот сервис не под J2EE, а с простым ява приложением.
Как все это реализовать на J2EE вполне понятно. Вся логика работы с транзакциями вынесена за рамки этого сервиса - внутри сервиса пользуется механизм DataSource и JNDI.

Но можно ли иметь что-то вроде UserTransaction в простом ява приложении?

спустя 2 дня 23 часа [обр] Виктор Сорока [досье]
Если кому интересно - могу рассказать до чего мы додумались
спустя 7 дней [обр] Денис Имаев [досье]
Виктор Сорока:
мы к примеру создали некие аналоги UserTransaction сами - это не сложно
спустя 1 день 5 часов [обр] Виктор Сорока [досье]

Денис Имаев:
В смысле полноценного UserTransaction?
а с поддержкой пула конектов?

мы в своем решении нашли глюки и пока приостановили двигаться в этом направлении вообще
можно поподробней узнать о том как именно это у вас работает?
интересно например откуда берется конект и тому подобное

спустя 23 часа [обр] Денис Имаев [досье]

Виктор Сорока:

допустим так, приблизительно: пул коннектов поддерживается отдельно, неким классом Util, который Вы инициализируете при старте.

а потом так:

Transaction transaction = null;

try 
{
  transaction = Util.beginTransaction();   // this will allocate a connection 
                                           // from the pool and disable autocommit 
                                           // for the duration
                                            
  Connection connection = transaction.getConnection();  // gets the connection

  .... // do things with the database using connection

  transaction.allowCommit();  // if we got here then everything's fine - permit the
                             // transaction to be committed
}
catch(...)     // error happened! need to rollback everything 
{
   ...        // in other words, we didn't get to the last line of the 'try' 
              // statement, and the transaction is not prepared to commit - 
              // it will roll back by default
}
finally 
{
   if (transaction != null)
       Util.endTransaction(transaction);    // this will commit or rollback and free the connection
}
спустя 17 часов [обр] Виктор Сорока [досье]

Денис Имаев:
то есть получается, что управление транзакциями Вы внесли в компонент?
как же тогда быть с Distributed transaction?

идея как раз вынести управление транзакциями за пределы компонента
в случае J2EE об этом будет думать контейнер

спустя 47 минут [обр] Денис Имаев [досье]

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

я может что-то капитально ошибочное говорю, но вот что:

ссылку на объект "транзакция" можно сделать удаленной (как бы) - то есть сами транзакции будут создаваться где-то централизованно.
а то, что конкретный бин хранит и пользуется своей собственной транзакцией - это же нормально. как же как в каждый момент времени кто-то один пользуется DB connection

спустя 28 минут [обр] Денис Имаев [досье]

в общем, в стандартном J2EE это делается примерно так:

Context myCntxt = new InitialContext();
UserTransaction ut =
    (UserTransaction) myCntxt.lookup("java:comp/UserTransaction");
ut.begin();
// perform transactional work here
ut.commit();

ну примерно то же, что я написал, только вместо JNDI и lookup транзакция берется откуда-то из другого "места":

transaction = Util.beginTransaction();

Util здесь как раз может быть некий централизованный ресурс.

спустя 10 минут [обр] Денис Имаев [досье]
давайте ко мне в джаву это перенесем? вроде имеет смысл
спустя 20 часов [обр] Виктор Сорока [досье]

Денис Имаев:
Давайте лучше здесь оставим :). О чем же тогда в этом форуме говорить? В названии ж прописано "... Backend-сервера".

проясню ситуацию
есть компонент который так сказать управляет транзакциями(процессор) и компоненты(сервисы) которые собственно пользуются конектами. Вот как раз сервисы и не должны осуществлять реальных комитов - решение принимается процессором.
Самое простое решение - снабжать декорированными конектами (что бы не комитили) сервисы

но так не очень нравится

спустя 2 часа 27 минут [обр] Денис Имаев [досье]

ну "backend-сервера" на джаве тоже пишутся и часть парадигмы, иначе что мы тут обсуждаем ;)) ну ладно.

а на каком основании процессор пример рещение, когда коммит а когда роллбэк?
в любом случае - компонент должен хоть как-то что-то сообщить процессору, что он уже закончил, или что-то произошло.

  1. эксепщн выбросить или нормальный выход.
  2. какой-то внутренний флаг в компоненте, по состоянию которого процессор определит что случилось.
  3. сообщение отправить

и т.д.

все это можно, но не проще ли все таки просить компонента коммитить самому? тогда реализация процессора упрощается.

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

спустя 2 дня 23 часа [обр] Виктор Сорока [досье]

Денис Имаев:
конечно узнать можно - JTA Transactions собственно для этого и были задуманы

пример:
имеем один процессор и несколько сервисов
комит только при успешном завершении работы всех сервисов

В J2EE все выглядит просто замечательно, пример из The J2EE Tutorial

UserTransaction ut = context.getUserTransaction();
try {
    ut.begin();
    updateChecking(amount);
    machineBalance -= amount;
    insertMachine(machineBalance);
    ut.commit();
} catch (Exception ex) {
    try {
        ut.rollback();
    } catch (SystemException syex) {
        throw new EJBException
              ("Rollback failed: " + syex.getMessage());
    }
    throw new EJBException
       ("Transaction failed: " + ex.getMessage());
}

а вот как бы все это и в J2SE окружении иметь

спустя 1 день 3 часа [обр] Денис Имаев [досье]

:)))
но я написал очень похожий участок кода, только вместо
UserTransaction ut = context.getUserTransaction();
у меня стоит
transaction = Util.beginTransaction();
то есть просто источник транзакций другой, а все остальное то же самое - ручной коммит в самом конце try блока, и роллбэк в случае ошибки.

поглядите.

спустя 30 минут [обр] Виктор Сорока [досье]

Денис Имаев:
да но вопрос то только в том как сервис получит конект!
между ut.begin() и ut.commit() происходит вызов различных сервисов
Иь при этом может происходить обращение к разным базам. В J2EE можно пользовать механизм DataSource и JNDI.

интересует то реализация в J2SE
как я уже писал, самое простое решение - снабжать декорированными конектами (что бы не комитили) сервисы
 
но так не очень нравится

спустя 1 час 41 минуту [обр] Денис Имаев [досье]
аааа я понял.
мы использовали решение при котором сервис снабжается транзакцией при вызове. если он не получает транзакцию, то он создает свою собственную.
спустя 27 минут [обр] Виктор Сорока [досье]
Денис Имаев:
свою собственную?
а как о ней узнает процессор? ему ж ее комитить
спустя 1 час 48 минут [обр] Денис Имаев [досье]

Виктор Сорока:

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

можно делать вот что - в процессоре создавать стэк вызовов и список открытых транзакций вместе с ссылками на тех, кто из открыл. тогда можно сделать авто-коммит.

вопрос только, нужны ли такие сложности?

спустя 15 часов [обр] Виктор Сорока [досье]

Денис Имаев:
как раз такое решение, на счет самостоятельного коммита и не подходит - решение о все коммитах принимает только процессор - при успешной отработке всех сервисов

а как сервису получать коннект в этом случае? Передавать при каждом вызове - но как я уже писал - так не нравится. Но похоже другого решения пока не наблюдается :(

спустя 2 часа 38 минут [обр] Денис Имаев [досье]

Виктор Сорока:

все равно не понимаю - почему сервис не может сам коммитить?

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

Вы хотите создать некий "процессор", который заменит J2EE Application Server и будет отслеживать транзакции и прочие вещи?
Но не слишком ли это сложное решение?
Стоит ли это того?
Не проще ли пойти на простое решение вроде того о чем мы говорим - передачи транзакции вызываемым сервисам?
Я вот к чему - за Application Server стоит много всякой лабуды, может не стоит это все переписывать только потому, что "не хочется заставлять сервисы коммитить самим".

спустя 2 часа 18 минут [обр] Виктор Сорока [досье]

Денис Имаев:
дело в том что не просто не хочется
а в том что нельзя сервису коммитить изменения - он не владеет информацией достаточной для принятия такого решения. Откуда ему знать как все прошло/пройдет у других
Все они выполняют одну большую задачу - частичное выполнение которой не конает.

В нашем проекте все это будет реализовано под J2EE. Но появилось у заказчика желание иметь возможность пользовать один из сервисов под J2SE. Ну не писать же его(сервис) два раза!

В данный момент реализуется решение с передачей коннекта (не вижу большого смысла в передаче транзакции) - простое решение. Но так не очень то нравится - таскать везде коннект.

В том то и дело что переписывать Application Server не хочется. Вот и интересует - может кто с таким сталкивался и как с этим боролся.

спустя 1 час 17 минут [обр] Денис Имаев [досье]

Виктор Сорока:
насчет того что сервису нельзя коммитить изменения - моржно, если он сам открывает транзакцию - в этом и смысл передачи ему транзакции извне, если нужно.
если он сам открыл транзакцию - сам ее и комитит, а если сверхзу получил - то не трогает.

ну ладно это уэен обсуждалось. я понял фишку - хочется и там и там.
будем думать

спустя 4 дня [обр] Денис Имаев [досье]

Виктор Сорока:

а что если посмотреть исходники какого-нить JBoss на тему как у них это реализовано? ;)) чтобы хоть идею какуб-нить оттуда стащить

Powered by POEM™ Engine Copyright © 2002-2005