@Transactional Spring не создает новую транзакцию

Любая помощь в этом будет принята с благодарностью. Я использую Spring, Jetty (плагин Eclipse Jetty). Похоже, декларативное управление транзакциями @Transactional не работает.

Подтверждено, что это не работает двумя способами: 1. Вновь созданный объект не сбрасывается в базу данных после вызова метода. 2. TransactionSynchronizationManager.isActualTransactionActive(); возвращает ложь

Обратите внимание, что приведенный ниже метод является отдельным для класса @Controller, где вызовы http-запроса в конечном итоге вызывают этот метод сохранения. Класс контроллера не реализует никаких интерфейсов. Фактический код:

 @Transactional(propagation = Propagation.REQUIRES_NEW)
  public void save(PERule peRule) {
     boolean inTransaction = TransactionSynchronizationManager.isActualTransactionActive();
            peRuleDAOImpl.persist(peRule);
     }

Отсутствие транзакции также подтверждается выводом журнала:

DEBUG: org.hibernate.internal.SessionImpl - Opened session at timestamp: 13762325621
DEBUG: org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl - Skipping
JTA sync registration due to auto join checking
DEBUG: org.hibernate.ejb.AbstractEntityManagerImpl - Looking for a JTA transaction to join
DEBUG: org.hibernate.ejb.AbstractEntityManagerImpl - Unable to join JTA transaction
DEBUG: org.hibernate.event.internal.AbstractSaveEventListener - Delaying identity-insert due to no transaction in progress

Однако, когда я программно определяю явные границы транзакций и фиксирую транзакцию, объект сбрасывается в базу данных. Например:

@Resource
private PlatformTransactionManager txManager; 
private void save(PERule peRule) {
    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
    TransactionStatus status = txManager.getTransaction(def);
    def.setName("SomeTxName");
    def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
    try {
        peRuleDAOImpl.persist(peRule);
    } catch (Exception ex) {
        txManager.rollback(status);
    }
    txManager.commit(status);
}

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

Контекстная конфигурация: root-context.xml

<aop:aspectj-autoproxy />  
<context:annotation-config />

 <context:component-scan
        base-package="org.springframework.samples.mvc, com.project.*" />


 <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location">
              <value>/WEB-INF/spring/proddatabase.properties</value>
         </property>
</bean>
 <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="jdbc/myds" />
</bean>

  <bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
   <property name="dataSource" ref="dataSource" />
    <property name="persistenceUnitName" value="EconDatesDB" />
    <property name="persistenceXmlLocation" value="/WEB-INF/spring/jpa-prod-persistence.xml" />
    <property name="jpaVendorAdapter">
         <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                    <property name="generateDdl" value="false" />
                    <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
        </bean>
   </property>
        <property name="jpaProperties">
              <props>
                    <prop key="hibernate.format_sql">false
                    </prop>
                    <prop key="hibernate.use_sql_comments">false
                    </prop>
                    <prop key="hibernate.generate_statistics">false
                    </prop>
                    <prop key="hibernate.transaction.factory_class">org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory
                    </prop>
                    <!-- The following line is what's used in Hibernate 4 instead of a TransactionManagerLookup 
                          class -->
                    <prop key="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup
                    </prop>

              </props>
        </property>
  </bean>
  <tx:annotation-driven mode="aspectj"  proxy-target-class="true" transaction-manager="transactionManager"/>


  <bean id="transactionManager"
        class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="transactionManager" ref="atomikosTransactionManager" />
        <property name="userTransaction" ref="atomikosUserTransaction" />
  </bean>

  <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
        <property name="transactionTimeout" value="300" />
  </bean>
  <!-- Construct Atomikos UserTransactionManager, needed to configure Spring -->
  <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
        init-method="init" destroy-method="close">
        <!-- when close is called, should we force transactions to terminate or 
              not? -->
        <property name="forceShutdown" value="false" />
        <property name="transactionTimeout" value="300" />
  </bean>


  <mvc:annotation-driven />

  <beans:bean id="conversionService"
        class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <beans:property name="formatters">
              <beans:bean
                    class="org.springframework.samples.mvc.convert.MaskFormatAnnotationFormatterFactory" />
        </beans:property>
  </beans:bean>

  <!-- Controllers.xml Only contains routes from path to view name, and has no other spring config
  <mvc:view-controller path="showcase/" view-name="/WEB-INF/views/home" /> -->
  <beans:import resource="/appServlet/controllers.xml" />  

сервлет-контекст:

      <resources mapping="/resources/**" location="/resources/" />
  <resources mapping="/sharedResources/**" location="/parkingEngine/resources/" />

  <beans:bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="order" value="1" />
        <!-- <beans:property name="prefix" value="/WEB-INF/views/" /> -->
        <beans:property name="prefix" value="" />
        <beans:property name="suffix" value=".jsp" />
  </beans:bean>

веб.xml:

      <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/root-context.xml</param-value>
  </context-param>


  <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>


  <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
              <param-name>contextConfigLocation</param-name>
              <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>
  </servlet-mapping>

pom.xml соответствующие зависимости:

<dependency>
              <groupId>cglib</groupId>
              <artifactId>cglib-nodep</artifactId>
              <version>2.2</version>
        </dependency>
        <dependency>
              <groupId>org.aspectj</groupId>
              <artifactId>aspectjweaver</artifactId>
              <version>1.6.10</version>
        </dependency>
        <dependency>
              <groupId>org.aspectj</groupId>
              <artifactId>aspectjrt</artifactId>
              <version>1.6.10</version>
        </dependency>

Я также пробовал следующие варианты tx:annotation-driven в моем root-context.xml:

<tx:annotation-driven mode="aspectj"  proxy-target-class="true" transaction-manager="transactionManager"/>
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>
<tx:annotation-driven />

person Shivam Sinha    schedule 11.08.2013    source источник


Ответы (1)


Как вы заметили, декларативное управление транзакциями основано на АОП. Это означает, что Spring оборачивает транзакционные компоненты в транзакционный прокси, который занимается запуском и фиксацией транзакций. Это означает, что вызов метода должен быть перехвачен прокси-сервером, чтобы быть транзакционным.

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

HTTP request --> controller.someUnknownMethod() --> controller.save()

Транзакционный метод должен находиться в отдельном bean-компоненте Spring (службе), вызываемом контроллером. Это заставит вызов проходить через прокси:

HTTP request --> controller.someUnknownMethod() --> transactional proxy --> service.save()

Это подробно объясняется в документации< /а>.

person JB Nizet    schedule 11.08.2013
comment
Привет, как было предложено, я создал интерфейс службы, реализовал интерфейс (ServiceImpl) и внедрил в него DAO (который содержал метод сохранения транзакций). Внедрил ServiceImpl в класс контроллера, и он по-прежнему дает тот же результат. Как будто прокси-классы не создаются. Я использую стандартный проект eclipse для очистки, а затем запускаю плагин, который запускает сервер. - person Shivam Sinha; 11.08.2013
comment
Привет. Я удалил transactionManager, atomikosUserTransaction и atomikosTransactionManager из своего корневого контекста. Настроил их в моем Jetty-Env.xml с включенным JNDI и поместил ‹tx:annotation-driven /›, чтобы Spring мог автоматически обнаруживать их в контейнере JNDI. Это также с предложением, сделанным выше, сработало. Благодарность - person Shivam Sinha; 12.08.2013
comment
исправление ops ‹tx:annotation-driven/› уже было в моем root-context.xml . Поместите ‹tx:jta-transaction-manager /› в мой корневой контекст для автоматического обнаружения диспетчера транзакций jndi jndi. - person Shivam Sinha; 12.08.2013