Главная » Spring » Программное управление транзакциями в Spring

0

Существуют два типа людей: любители покомандовать и те, кто командовать не любит. Любители покомандовать стремятся контро- лировать все и вся, и никому не доверяют. Если вы – разработчик и любите покомандовать, вы наверняка относитесь к числу людей, предпочитающих командную строку, и пишете свои методы доступа к свойствам, не доверяя эту работу среде разработки.

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

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

В качестве примера метода, выполняемого в рамках транзакции, возьмем метод saveSpittle() класса SpitterServiceImpl,  представлен- ный в листинге 7.1.

Листинг 7.1. Метод saveSpittle() сохраняет объект Spittle

public  void  saveSpittle(Spittle  spittle)  { spitterDao.saveSpittle(spittle);

}

Несмотря на кажущуюся простоту, в этом методе могут выпол- няться довольно сложные операции, невидимые на первый взгляд. В процессе сохранения объекта Spittle механизм хранения данных может выполнять множество действий. Даже если сохранение сво- дится к простой вставке строки в таблицу базы данных, важно убе- диться, что все операции выполняются в рамках транзакции. Если все операции будут выполнены успешно, транзакцию можно под- твердить. Если что-то пойдет не так, ее можно отменить.

Один из подходов к включению транзакций в работу заключается в добавлении транзакции программно, непосредственно внутри ме- тода saveSpittle(), с использованием класса шаблона TransactionTemp- late. Подобно другим классам шаблонов в Spring (таким как класс JdbcTemplate, обсуждавшийся в предыдущей главе), TransactionTemplate использует механизм обратных вызовов. В листинге 7.2 приводится измененная версия метода saveSpittle(), демонстрирующая, как до- бавлять транзакции с помощью TransactionTemplate.

Листинг 7.2. Программное добавление транзакции в метод saveSpittle()

public  void  saveSpittle(final  Spittle  spittle)  { txTemplate.execute(new  TransactionCallback<Void>()  {

public  Void  doInTransaction(TransactionStatus  txStatus)  { try  {

spitterDao.saveSpittle(spittle);

} catch (RuntimeException e) { txStatus.setRollbackOnly(); throw e;

}

});

}

}

return null;

Чтобы иметь возможность использовать класс TransactionTemplate, необходимо сначала реализовать интерфейс TransactionCallback. Так как интерфейс TransactionCallback определяет единственный метод, часто бывает проще реализовать его в виде анонимного вложенного

класса, как показано в листинге 7.2. А программный код, который должен выполняться в рамках транзакции, должен находиться внут- ри метода doInTransaction().

Вызов метода execute() экземпляра класса TransactionTemplate вы- полнит программный  код  внутри  экземпляра  TransactionCallback. В случае появления проблемы будет вызван метод setRollbackOnly() объекта TransactionStatus, чтобы отменить транзакцию. В противном случае, если метод doInTransaction() благополучно вернул управле- ние, транзакция будет подтверждена.

А откуда здесь возьмется экземпляр TransactionTemplate? Хороший вопрос. Он должен быть внедрен в компонент SpitterServiceImpl, как показано ниже:

<bean  id="spitterService" class="com.habuma.spitter.service.SpitterServiceImpl">

<property  name="transactionTemplate  ">

<bean    class=”org.springframework.transaction.support.

TransactionTemplate”>

<property name=”transactionManager” ref=”transactionManager”   />

</bean>

</property>

</bean>

Обратите внимание на наличие в компоненте TransactionTemplate свойства transactionManager. За кулисами компонент TransactionTemplate использует реализацию интерфейса PlatformTransactionManager для обслуживания особенностей транзакций для конкретной платфор- мы. Здесь в свойство внедряется ссылка на компонент с именем transactionManager, который может быть любым диспетчером транз- акций из числа перечисленных в табл. 7.1.

Программное управление транзакциями отлично подходит для ситуаций, когда требуется иметь полный контроль над границами транзакций. Но, как видно из листинга 7.2, это достаточно утоми- тельно. Необходимо изменить реализацию метода saveSpittle() – ис- пользовать классы из фреймворка Spring, чтобы ввести в действие поддержку программного управления транзакциями в Spring.

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

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

Источник:   Уоллс К., Spring в действии. – М.: ДМК Пресс, 2013. – 752 с.: ил.

По теме:

  • Комментарии