Транзакции в J2EE
Содержание
1 Что такое транзакция?
2 Управляемые контейнером транзакции
 2.1; Атрибуты транзакции
 2.1.1; Required
 2.1.2; RequiresNew
 2.1.3; Mandatory
 2.1.4; NotSupported
 2.1.5; Supports
 2.1.6; Never
 2.1.7; Резюме по атрибутам транзакции
 2.1.8; Установка атрибутов транзакции
 2.2; Откат управляемой контейнером транзакции
 2.3; Синхронизация переменных экземпляра сессионного компонента
 2.4; Методы, не разрешенные в управляемых контейнером транзакциях
3 Управляемые компонентом транзакции
 3.1; JDBC-транзакции
 3.1.1; Исходный код
 3.2; JTA-транзакции
 3.3; Возврат без подтверждения
 3.4; Методы, не разрешенные в управляемых компонентом транзакциях
4 Сводка опций транзакции для корпоративных компонентов
5 Таймауты транзакции
6 Уровни изоляции
7 Обновление нескольких баз данных
8 Транзакции в Web-компонентах
1 Что такое транзакция?
Для имитации бизнес-транзакции в программе может потребоваться выполнение нескольких шагов. Финансовая программа, например, может перечислить финансовые средства с текущего счета на депозитный счет, выполнив шаги, перечисленные в следующем псевдокоде:
начало транзакции
дебет текущего счета
кредит депозитного счета
обновление журнала истории
подтверждение транзакции
Должны выполниться или все три шага, или ни одного. В противном случае, целостность данных будет нарушена. Поскольку шаги внутри транзакции рассматриваются как одно целое, транзакция часто определяется как неделимая единица работы.
Транзакция может закончиться двумя операциями: подтверждением или откатом. Когда транзакция подтверждается, изменения данных, произведенные операторами транзакции, сохраняются. Если оператор внутри транзакции завершается аварийно, происходит откат транзакции и аннулируется результат работы всех операторов в транзакции. В псевдокоде, например, если накопитель на дисках сломается во время шага кредит, произойдет откат транзакции и аннулируется изменение данных, сделанное оператором дебет. Хотя транзакция не выполнилась, целостность данных не будет нарушенной, поскольку счета остались сбалансированными.
В предыдущем псевдокоде операторы начало и подтверждение отмечают границы транзакции. При проектировании корпоративного компонента вы определяете, как устанавливаются границы, при помощи указания транзакций либо управляемых контейнером, либо управляемых компонентом.
2 Управляемые контейнером транзакции
В корпоративном компоненте с управляемыми контейнером транзакциями границы транзакции устанавливаются EJB-контейнером. Вы можете использовать управляемые контейнером транзакции с любым типом корпоративных компонентов: сессионными, управления данными или управляемых сообщениями. Управляемые контейнером транзакции упрощают разработку, поскольку код корпоративного компонента не отмечает явно границы транзакции. Код не содержит операторов, которые начинают и заканчивают транзакцию.
Обычно, контейнер начинает транзакцию непосредственно перед началом метода корпоративного компонента. Он подтверждает транзакцию перед выходом из метода. Каждый метод может быть связан только с одной транзакцией. Вложенные или многочисленные транзакции не разрешены внутри метода.
Управляемые контейнером транзакции не требуют, чтобы все методы были связаны с транзакциями. При размещении компонента вы указываете, какой из методов компонента связан с транзакциями, при помощи установки атрибутов транзакции.
2.1 Атрибуты транзакции
Атрибуты транзакции управляют областью видимости транзакции. На рисунке 14-1 показано, почему управление областью видимости так важно. На диаграмме method-A начинает транзакцию и затем вызывает method-B или Bean-2. Где выполняется method-B? Работает ли он внутри области видимости транзакции, начатой в method-A, или он выполняется с новой транзакцией? Ответ зависит от атрибута method-B.
Рисунок 14-1 Область видимости транзакции
Атрибут транзакции может иметь одно из следующих значений:
-
Required
-
RequiresNew
-
Mandatory
-
NotSuported
-
Supports
-
Never
2.1.1 Required
Если клиент работает внутри транзакции и вызывает метод корпоративного компонента, этот метод выполняется в транзакции клиента. Если клиент не работает в транзакции, контейнер запускает новую транзакцию перед выполнением метода.
Атрибут Required будет работать для большинства транзакций. Поэтому вы можете использовать его по умолчанию, по крайней мере, на ранних стадиях разработки. Поскольку атрибуты транзакции являются декларативными, их можно потом легко поменять.
2.1.2 RequiresNew
Если клиент работает внутри транзакции и вызывает метод корпоративного компонента, контейнер выполняет следующие действия:
-
Приостанавливает клиентскую транзакцию.
-
Начинает новую транзакцию.
-
Посылает запрос в метод.
-
Продолжает клиентскую транзакцию после завершения метода.
Если клиент не работает в транзакции, контейнер запускает новую транзакцию перед выполнением метода.
Вы должны использовать атрибут RequiresNew тогда, когда захотите, чтобы метод всегда выполнялся в новой транзакции.
2.1.3 Mandatory
Если клиент работает внутри транзакции и вызывает метод корпоративного компонента, метод выполняется внутри клиентской транзакции. Если клиент не работает в транзакции, контейнер генерирует исключительную ситуацию TransactionRequiredException.
Используйте атрибут Mandatory в тех случаях, когда метод корпоративного компонента должен использовать клиентскую транзакцию.
2.1.4 NotSupported
Если клиент работает внутри транзакции и вызывает метод корпоративного компонента, контейнер приостанавливает клиентскую транзакцию перед вызовом метода. После завершения метода контейнер продолжает клиентскую транзакцию.
Если клиент не работает в транзакции, контейнер запускает новую транзакцию перед выполнением метода.
Используйте атрибут NotSupported для методов, не требующих транзакций. Поскольку транзакции увеличивают накладные расходы, этот атрибут может улучшить производительность.
2.1.5 Supports
Если клиент работает внутри транзакции и вызывает метод корпоративного компонента, метод выполняется внутри клиентской транзакции. Если клиент не работает в транзакции, контейнер не запускает новую транзакцию перед выполнением метода.
Поскольку поведение метода в отношении транзакций может меняться, вы должны с осторожностью использовать атрибут Supports.
2.1.6 Never
Если клиент работает внутри транзакции и вызывает метод корпоративного компонента, контейнер генерирует исключительную ситуацию RemoteException. Если клиент не работает в транзакции, контейнер не запускает новую транзакцию перед выполнением метода.
2.1.7 Резюме по атрибутам транзакции
В таблицу 14-1 сведены результаты работы при использовании атрибутов транзакции. И транзакция Т1, и транзакция Т2 управляются контейнером. Транзакция Т1 связана с клиентом, который вызывает метод в корпоративном компоненте. В большинстве случаев клиент также является корпоративным компонентом. Транзакция Т2 запускается контейнером перед выполнением метода.
В последнем столбце таблицы 14-1 слово None обозначает, что бизнес-метод не выполняется в транзакции, управляемой контейнером. Однако, вызовы базы данных в таких бизнес-методах могут управляться менеджером транзакций DBMS.
2.1.8 Установка атрибутов транзакции
Поскольку атрибуты транзакции хранятся в дескрипторе размещения, они могут быть изменены на нескольких фазах разработки J2EE-приложения: создание корпоративного компонента, сборка приложения и размещение. Однако, за установку атрибутов несет ответственность разработчик корпоративного компонента при создании компонента. Атрибуты должны изменяться только разработчиком приложения, который собирает компоненты в большие приложения. Не ожидайте, что человек, размещающий J2EE-приложение, укажет атрибуты транзакции.
Таблица 14-1 Атрибуты транзакции и область видимости
Атрибут транзакции | Транзакция клиента | Транзакция бизнес-метода |
---|---|---|
Required | None | T2 |
T1 | T1 | |
RequiresNew | None | T2 |
T1 | T2 | |
Mandatory | None | error |
T1 | T1 | |
NotSupported | None | None |
T1 | None | |
Supports | None | None |
T1 | T1 | |
Never | None | None |
T1 | Error |
Атрибуты транзакции можно указать для корпоративного компонента в целом или для его отдельных методов. Если указывается один атрибут для метода, а другой для компонента, атрибут для метода имеет преимущество. Требования при указании атрибутов для отдельных методов зависят от типа компонента. Сессионные компоненты требуют определения атрибутов для бизнес-методов, но не позволяют их для методов create. Компоненты управления данными требуют атрибуты транзакции для бизнес-методов, методов create, remove и методов поиска. Управляемые сообщениями компоненты требуют атрибуты транзакции (либо Required, либо NotSupported) для метода onMessage.
2.2 Откат управляемой контейнером транзакции
Существует два способа произвести откат управляемой контейнером транзакции. Первый - при возникновении системной исключительной ситуации контейнер автоматически произведет откат транзакции. Второй - вызывая метод setRollbackOnly интерфейса EJBContext, метод компонента дает указание контейнеру произвести откат транзакции. Если компонент генерирует программную исключительную ситуацию, откат не происходит автоматически, но может быть запущен при помощи вызова setRollbackOnly. Описание системных и программных исключительных ситуаций находится в разделе Обработка исключительных ситуаций.
Исходный код следующего примера расположен в каталоге j2eetutorial/examples/src/ejb/bank. Чтобы откомпилировать код перейдите в каталог j2etutorial/examples и выполните команду ant bank. Для создания таблиц базы данных выполните команду ant create-bank-table. Файл примера BankApp.ear находится в каталоге j2eetutorial/examples/ears.
Метод transferToSaving примера BankEJB демонстрирует метод setRollbackOnly. При возникновении ситуации "отрицательный баланс счета" transferToSaving вызывает setRollBackOnly и генерирует программную исключительную ситуацию (InsufficientBalanceException). Методы updateChecking и updateSaving обновляют таблицы базы данных. Если обновление происходит неудачно, эти методы генерируют SQLException и метод transferToSaving генерирует EJBException. Поскольку EJBException является системной исключительной ситуацией, она заставляет контейнер автоматически произвести откат транзакции. Ниже приведен исходный код метода transferToSaving:
public void transferToSaving(double amount) throws
InsufficientBalanceException {
checkingBalance -= amount;
savingBalance += amount;
try {
updateChecking(checkingBalance);
if (checkingBalance < 0.00) {
context.setRollbackOnly();
throw new InsufficientBalanceException();
}
updateSaving(savingBalance);
} catch (SQLException ex) {
throw new EJBException
("Transaction failed due to SQLException: "
+ ex.getMessage());
}
}
Когда контейнер производит откат транзакции, он всегда отменяет изменения данных, сделанные SQL-запросами внутри транзакции. Однако только в компонентах управления данными контейнер будет аннулировать изменения, сделанные в переменных экземпляра. (Он делает это автоматически, вызывая метод ejbLoad компонента управления данными, который загружает значения из базы данных в переменные экземпляра.) При откате транзакции сессионный компонент должен явно восстановить все переменные экземпляра, измененные внутри транзакции. Самым простым способом восстановления переменных экземпляра сессионного компонента является реализация интерфейса SessionSynchronization.
2.3 Синхронизация переменных экземпляра сессионного компонента
Интерфейс SessionSynchronization, являющийся не обязательным, позволяет синхронизировать переменные экземпляра с их соответствующими значениями в базе данных. Контейнер вызывает методы SessionSynchronization - afterBegin, beforeCompletion и afterCompletion - на каждой из основных стадий транзакции.
Метод afterBegin информирует экземпляр о начале транзакции. Контейнер вызывает afterBegin непосредственно перед вызовом бизнес-метода. Метод afterBegin является хорошим местом для загрузки переменных экземпляра из базы данных. Класс BankBean, например, загружает переменные checkingBalance и savingBalance в метод afterBegin:
public void afterBegin() {
System.out.println("afterBegin()");
try {
checkingBalance = selectChecking();
savingBalance = selectSaving();
} catch (SQLException ex) {
throw new EJBException("afterBegin Exception: " +
ex.getMessage());
}
}
Контейнер вызывает метод beforeCompletion после завершения бизнес-метода, но непосредствено перед подтверждением транзакции. Метод beforeCompletion является последней возможностью для сессионного компонента сделать откат транзакции (вызвав setRollbackOnly). Если значения переменных экземпляра еще не были обновлены в базе данных, сессионный компонент может сделать это в методе beforeCompletion.
Метод afterCompletion служит признаком того, что транзакция завершилась. Он имеет один параметр boolean, чье значение равно true, если транзакция была подтверждена, и false, если произошел ее откат. При возникновении отката транзакции сессионный компонент может обновить свои переменные экземпляра из базы данных в методе afterCompletion:
public void afterCompletion(boolean committed) {
System.out.println("afterCompletion: " + committed);
if (committed == false) {
try {
checkingBalance = selectChecking();
savingBalance = selectSaving();
} catch (SQLException ex) {
throw new EJBException("afterCompletion SQLException:
" + ex.getMessage());
}
}
}
2.4 Методы, не разрешенные в управляемых контейнером транзакциях
Вы не должны вызывать никакие методы, которые могут вступить в противоречие с границами транзакции, установленными контейнером. Список запрещенных методов следующий:
Методы commit, setAutoCommit и rollback интерфейса java.sql.Connection.
Метод getUserTransaction интерфейса javax.ejb.EJBContext
Любой метод интерфейса javax.transaction.UserTransaction.
Можно, тем не менее, использовать эти методы для установки границ управляемых компонентом транзакций.
3 Управляемые компонентом транзакции
В управляемой компонентом транзакции код в сессионном или управляемом сообщениями компоненте явно отмечает границы транзакции. Компонент управления данными не может использовать управляемые компонентом транзакции; он должен использовать управляемые контейнером транзакции. Хотя компоненты с управляемыми контейнером транзакциями требует меньше кодирования, они имеют одно ограничение: когда метод выполняется, он может быть связан либо с одной транзакцией, либо ни с одной. Если это ограничение сделает трудным кодирование вашего компонента, вы должны использовать управляемые компонентом транзакции.
Следующий псевдокод иллюстрирует тип мелкомодульного управления, которое можно получить при помощи управляемых компонентом транзакций. Проверяя различные условия, псевдокод принимает решение начать или завершить различные транзакции в бизнес-методе.
begin transaction
...
update table-a
...
if (condition-x)
commit transaction
else if (condition-y)
update table-b
commit transaction
else
rollback transaction
begin transaction
update table-c
commit transaction
При кодировании управляемой компонентом транзакции для сессионного или управляемого сообщениями компонента вы должны решить, использовать ли JDBC, или JTA-транзакции. В следующем разделе рассматриваются оба типа транзакций.
3.1 JDBC-транзакции
JDBC-транзакция управляется менеджером транзакций DBMS. Вы, возможно, захотите использовать JDBC-транзакции при помещении существующего кода в сессионный компонент. Чтобы закодировать JDBC-транзакцию, надо вызвать методы commit и rollback интерфейса java.sql.Connection. Начало транзакции происходит неявно. Транзакция начинается с первым SQL-оператором, который следует за самым последним оператором commit, rollback или connect. (Это правило обычно выполняется, но зависит от поставщика DBMS.)
3.1.1 Исходный код
Исходный код следующего примера находится в каталоге j2eetutorial/examples/src/ejb/warehouse. Чтобы откомпилировать программу, перейдите в каталог j2eetutorial/examples и выполните команду ant bank. Для создания таблиц базы данных выполните команду ant create-warehouse-table. Файл примера WarehouseApp.ear находится в каталоге j2eetutorial/examples/ears.
Ниже приведен код из примера WarehouseEJB - сессионного компонента, использующего методы интерфейса Connection для разграничения управляемых компонентом транзакций. Метод ship начинается вызовом setAutoCommit объекта Connection с именем con. Этот вызов указывает DBMS не подтверждать автоматически каждый SQL-оператор. Затем метод ship вызывает процедуры, обновляющие таблицы базы данных order_item и inventory. Если обновления завершаются успешно, транзакция подтверждается. Если генерируется исключительная ситуация, происходит откат транзакции.
public void ship (String productId, String orderId, int
quantity) {
try {
con.setAutoCommit(false);
updateOrderItem(productId, orderId);
updateInventory(productId, quantity);
con.commit();
} catch (Exception ex) {
try {
con.rollback();
throw new EJBException("Transaction failed: " +
ex.getMessage());
} catch (SQLException sqx) {
throw new EJBException("Rollback failed: " +
sqx.getMessage());
}
}
}
3.2 JTA-транзакции
JTA представляет собой аббревиатуру Java Transaction API. Это API позволяет разграничить транзакции способом, независящим от реализации менеджера транзакций. J2EE SDK реализует менеджер транзакций при помощи Java Transaction Service (JTS). Но в коде эти методы не вызываются прямо. Вместо этого, вызываются JTA-методы, которые, в свою очередь, вызывают JTS-процедуры низкого уровня.
JTA-транзакции управляются менеджером транзакций J2EE. Вы, вероятно, захотите использовать JTA-транзакцию потому, что она может обновлять нескольких баз данных от разных поставщиков. Менеджер транзакций конкретной DBMS может не работать с гетерогенными базами данных. Однако, менеджер транзакций J2EE имеет одно ограничение - он не поддерживает вложенных транзакций. Другими словами, он не может начать транзакцию для экземпляра пока предыдущая транзакция не закончится.
Исходный код следующего примера расположен в каталоге j2eetutorial/examples/src/ejb/teller. Чтобы откомпилировать этот код, выполните команду ant teller. Для создания таблиц базы данных выполните команду ant create-bank-teller. Файл примера TellerApp.ear находится в каталоге j2eetutorial/examples/ears.
Для того чтобы разграничить транзакцию, нужно вызвать методы begin, commit и rollback интерфейса javax.transaction.UserTransaction. Приведенный ниже код, взятый из класса TellerBean, демонстрирует методы UserTransaction. Вызовы begin и commit определяют границы обновлений базы данных. Если обновления заканчиваются неудачно, код вызывает метод roolback и генерирует EJBException.
public void withdrawCash(double amount) {
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());
}
}
3.3 Возврат без подтверждения
В сессионном компоненте, не сохраняющем состояния и использующем управляемые компонентом транзакции, бизнес-метод должен подтвердить транзакцию или произвести откат транзакции перед возвратом. Однако, сессионный компонент, сохраняющий состояние, не имеет этого ограничения.
В сессионном компоненте, сохраняющем состояние и использующем JTA-транзакцию, взаимосвязь между экземпляром компонента и транзакцией поддерживается между несколькими клиентскими вызовами. Даже если бизнес-метод, вызванный клиентом, открывает и закрывает соединение с базой данных, взаимосвязь сохраняется до тех пор, пока экземпляр не завершит транзакцию.
В сессионном компоненте, сохраняющем состояние и использующем JDBC-транзакцию, JDBC-соединение сохраняет взаимосвязь между экземпляром компонента и транзакцией между несколькими вызовами. Если соединение закрывается, взаимосвязь не сохраняется.
3.4 Методы, не разрешенные в управляемых компонентом транзакциях
Не вызывайте методы getRollbackOnly и setRollbackOnly интерфейса EJBContext в управляемых компонентом транзакциях. Эти методы должны использоваться только в транзакциях, управляемых контейнером. Для управляемых компонентом транзакций вызываются методы getStatus и rollback интерфейса UserTransaction.
4 Сводка опций транзакции для корпоративных компонентов
Если вы не уверены в том, как установить транзакции в корпоративном компоненте, вот небольшой совет: в дескрипторе размещения компонента укажите управляемые контейнером транзакции. Затем установите атрибут Required для всего компонента. Этот подход будет работать в большинстве случаев.
В таблице 14-2 перечислены типы транзакций, которые разрешены для различных типов корпоративных компонентов. Компонент управления данными должен использовать управляемые контейнером транзакции. При использовании управляемых контейнером транзакций атрибуты транзакции указываются в дескрипторе размещения, а откат транзакции производится при помощи метода setRollbackOnly интерфейса EJBContext.
Таблица 14-2 Разрешенные типы транзакции для корпоративных компонентов.
Управляемые контейнером | Управляемые компонентом | ||
---|---|---|---|
JTA | JDBC | ||
Управления данными | Y | N | N |
Сессионный | Y | Y | Y |
Управляемый сообщениями | Y | Y | Y |
Сессионный компонент может использовать как управляемые контейнером, так и управляемые компонентом транзакции. Существует два типа управляемых компонентом транзакций: JDBC и JTA-транзакции. JDBC-транзакции разграничиваются методами commit и rollback интерфейса Connection. Для разграничения JTA-транзакций используются методы begin, commit и rollback интерфейса UserTransaction.
В сессионном компоненте с управляемыми компонентом транзакциями возможно смешивать JDBC и JTA-транзакции. Однако такая практика не рекомендуется, поскольку может сделать код сложным для отладки и поддержки.
Аналогично сессионному компоненту, управляемый сообщениями компонент может использовать как управляемые контейнером, так и управляемые компонентом транзакции.
5 Таймауты транзакции
Для управляемых контейнером транзакций значение таймаута транзакции устанавливается указанием значения свойства transaction.timeout в файле default.properties, который находится в подкаталоге config каталога установки J2EE SDK. Например, вы могли бы установить значение таймаута равным 5 секундам следующим образом:
transaction.timeout=5
При этой установке, если транзакция не завершилась в течение 5 секунд, EJB-контейнер произведет ее откат.
При первой установке J2EE SDK значение таймаута установлено в 0:
transaction.timeout=0
Если значение равно 0, транзакции не ограничиваются по времени.
Только корпоративные компоненты с управляемыми контейнером транзакциями зависят от свойства transaction.timeout. Для корпоративных компонентов с управляемыми компонентом JTA-транзакциями вызывается метод setTransactionTimeout интерфейса UserTransaction.
6 Уровни изоляции
Транзакции не только гарантируют полное завершение (или откат) операторов, которые они охватывают, но также изолируют данные, измененные операторами. Уровень изоляции описывает степень видимости измененных данных для других транзакций.
Предположим, что транзакция в одной программе обновляет номер телефона заказчика, но перед подтверждением транзакции другая программа читает тот же самый номер. Прочитает ли вторая программа новый и не подтвержденный номер телефона, или будет читать старый? Ответ зависит от уровня изоляции транзакции. Если транзакция разрешает другим программам читать не подтвержденные данные, производительность может улучшиться, поскольку другая программа не должна ожидать окончания транзакции. Но здесь присутствует компромисс - если транзакция будет отменена, другая программа может прочитать ошибочные данные.
Вы не можете изменить уровень изоляции компонента управления данными с управляемой контейнером персистенцией. Эти компоненты по умолчанию используют уровень изоляции DBMS, который обычно установлен в READ_COMMITED.
Для компонентов управления данными с управляемой компонентом персистенцией и для всех сессионных компонентов можно программно установить уровень изоляции, используя API, предоставленный применяемой DBMS. DBMS, например, может позволить вам выполнять не подтвержденные чтения при помощи вызова метода setTransactionIsolation:
Connection con;
...
con.setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED);
Не меняйте уровень изоляции в середине транзакции. Обычно такое изменение вызывает выполнение программным обеспечением DBMS неявного подтверждения. Поскольку уровни изоляции, предлагаемые различными поставщиками DBMS, могут меняться, вы должны обратиться к документации DBMS за дополнительной информацией. Уровни изоляции не стандартизованы для платформы J2EE.
7 Обновление нескольких баз данных
Менеджер транзакций J2EE управляет всеми транзакциями корпоративного компонента за исключением управляемых компонентом JDBC-транзакций. Менеджер транзакций J2EE разрешает корпоративному компоненту обновлять несколько баз данных в одной транзакции.
На рисунке 14-2 показано, как клиент вызывает бизнес-метод в компоненте Bean-A. Бизнес-метод начинает транзакцию, обновляет Database X, обновляет Database Н и вызывает бизнес-метод в компоненте Bean-B. Второй бизнес-метод обновляет Database Z и возвращает управление в бизнес-метод компонента Bean-A, который подтверждает транзакцию. Обновление всех трех баз данных происходит в одной транзакции.
Рисунок 14-2 Обновление нескольких баз данных
На рисунке 14-3 показано, как клиент вызывает бизнес-метод компонента Bean-A, который начинает транзакцию и обновляет Database X. Затем Bean-A вызывает метод в компоненте Bean-B, который расположен на удаленном J2EE-сервере. Метод в Bean-B обновляет Database Y. Менеджеры транзакций J2EE-серверов гарантируют, что обе базы данных обновляются в одной и той же транзакции.
Рисунок 14-3 Обновление нескольких баз данных с несколькими J2EE-серверами
8 Транзакции в Web-компонентах
Вы можете разграничить транзакцию в Web-компоненте при помощи интерфейсов java.sql.Connection или javax.transaction.UserTransaction. Это те же самые интерфейсы, которые может использовать сессионный компонент с управляемыми компонентом транзакциями. Транзакции, разграниченные при использовании интерфейса Connection, рассматриваются в разделе JDBC-транзакции, а разграниченные при использовании интерфейса UserTransaction, в разделе JTA-транзакции. Пример Web-компонента, использующего транзакции, рассмотрен в разделе Обращение к базам данных.