Spring Jdbc декларативные транзакции созданы, но ничего не делают - PullRequest
2 голосов
/ 31 марта 2011

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

У меня есть две основные проблемы:

  1. Установка для defaultAutoCommit значения false в нашем источнике данных (который нам нужен для нашего приложения) приводит к откату всех запросов с участием транзакций или без них.
  2. Транзакции настроены и созданы прокси-классы, а также транзакционные методы, однако транзакции, похоже, не используются.

Первая проблема довольно запутанная, поскольку каждый отдельный запрос откатывается в базе данных. Это включает и операторы SELECT. Что может вызвать откат каждого запроса в базе данных?

Что касается второй проблемы, моя конфигурация управления транзакциями описана ниже:

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://springframework.org/schema/context"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/spring-context-3.0.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"
       default-autowire="byName">

<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->
<tx:advice id="txAdvice" transaction-manager="txManager">
  <!-- the transactional semantics... -->
  <tx:attributes>
    <!-- other methods use the default transaction settings (see below) -->
    <tx:method name="*" rollback-for="Exception" />
  </tx:attributes>
</tx:advice>

<!-- ensure that the above transactional advice runs for any execution
 of an operation defined by a service in the service package -->
<aop:config>
  <aop:pointcut id="serviceOperations" expression="execution(* foo.bar.service.*.*(..))"/>
  <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperations"/>
</aop:config>

<!-- similarly, don't forget the PlatformTransactionManager -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
</bean>

<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
    <property name="defaultAutoCommit" value="false" />
</bean>

<bean id="fooService" class="foo.bar.service.FooService" />

<bean id="barService" class="foo.bar.service.BarService" />

<bean id="zapService" class="foo.bar.service.ZapService" />

</beans>

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

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

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

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

Мой log4j настроен со следующими регистраторами, чтобы попытаться отследить транзакции:

log4j.logger.org.springframework=INFO, file
log4j.logger.org.springframework.jdbc.datasource=DEBUG, file
log4j.logger.org.springframework.transaction=DEBUG, file

Примечание. В какой-то момент я запустил ведущий регистратор на DEBUG, и именно там я убедился, что создаются прокси служб.

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

Редактировать

Дополнительная информация по запросу JB Nizet.

Все мое приложение управляется аннотациями, и поэтому мои служебные бины снабжаются аннотациями @Service и внедряются в мои контроллеры с помощью автоматического подключения на основе имен.

Ниже приведен пример одного из моих классов обслуживания (имена были изменены, но будут отражать мой applicationContext.xml).

@Service("zapService")
public class ZapService
{

    /**
     * Data access object which performs the database look up
     */
    private ZapDAO zapDAO;

    /**
     * Add the given zap to the database
     *
     * @param zap a populated zap
     */
    public void processNewZap(Zap zap)
    {
        zapDAO.processNewZap(zap);
    }
}

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

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

Класс ZapDAO описан ниже.

@Repository("zapDAO")
public class ZapDAO
{

    /**
     * Log4j logger for this class
     */
    Logger logger = Logger.getLogger(ZapDAO.class);

    /**
     * Spring jdbc object to handle interacting with the database
     */
    private JdbcTemplate jdbcTemplate;

    public void processNewZap(Zap zap) {

        ... query constructing logic ...

        this.jdbcTemplate.update(INSERT_ZAP_QUERY_SQL);

    }

    public void setDataSource(DataSource dataSource)
    {
        Assert.notNull(dataSource, "You must supply a valid data source");

        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
}

Я использую jdbcTemplate для обработки моих соединений и запросов.

1 Ответ

3 голосов
/ 01 апреля 2011

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

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

Внутри моего dispatch-servlet.xml я первоначально объявил свое сканирование компонентов следующим образом:

<context:component-scan base-package="foo.bar"/>

Который является родительским пакетом для всех моих компонентов приложения.Итак, как описано в приведенной выше ссылке, Spring переписывал мои транзакционные сервисные компоненты из applicationContext.xml служебными компонентами из dispatcher-servlet.xml, который не знал о транзакциях.

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

<context:component-scan base-package="foo.bar.controller"/>
<context:component-scan base-package="foo.bar.model"/>
<context:component-scan base-package="foo.bar.service.display"/>
<context:component-scan base-package="foo.bar.service.security"/>

<!-- foo.bar.service gets scanned in applicationContext.xml and includes 
transactions so we must make sure to not include it here. The transactional beans
will be overridden in that case -->

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

...