Spring @Transactional не работает с другими аннотациями? - PullRequest
3 голосов
/ 14 октября 2011

Так что мое весеннее образование продолжается. В настоящее время я пытаюсь изучить некоторые аннотации и то, что они привносят в Spring 3. Итак, у меня есть мини-веб-приложение, которое может подключаться к БД и вводить данные через форму, отображать записи и так далее. Все отлично работает Я решил попробовать и заставить Spring автоматически определять компонент службы, который я пометил как @Transactional, но при этом приложение не может сохранить приложение в БД. Итак:

@Transactional
public class ReservationServiceImpl implements ReservationService {

это работает. У меня есть объявление bean-объекта этого класса в моих файлах springcourt-data.xml. Нет проблем. Когда я делаю это, хотя:

@Transacational
@Service("reservationService")
public class ReservationServiceImpl implements ReservationService {

больше не работает. И у меня есть

<context:component-scan base-package="com.springcourt" />

в файле springcourt-servlet.xml. Так может кто-нибудь сказать мне, что я облажался? Все, что я делаю, это добавляю еще одну аннотацию к этому классу и удаляю определение bean-компонента из файла xml, и он больше не сохраняет данные в БД. Я по-прежнему могу запрашивать записи и прочее из БД, хотя очевидно, что он использует служебный компонент с автоматически определенными функциями.

Вот файлы конфигурации:

springcourt-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

<context:component-scan base-package="com.springcourt" />

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="webBindingInitializer">
        <bean class="com.springcourt.web.ReservationBindingInitializer" />
    </property>
</bean>

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>
</beans>

И

springcourt-data.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
        <bean
            class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="database" value="MYSQL" />
            <property name="showSql" value="true" />
        </bean>
    </property>
</bean>

<bean id="dataSource"
        class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/test" />
    <property name="username" value="root" />
    <property name="password" value="admin" />
    <property name="initialSize" value="5" />
</bean>

<bean id="transactionManager"
    class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<tx:annotation-driven />

<bean id="reservationService" class="com.springcourt.service.ReservationServiceImpl"/>
</beans>

Ответы [ 5 ]

3 голосов
/ 15 октября 2011

Когда вы используете @Service и компонентное сканирование, бин создается контекстом, созданным сервлетом диспетчера (mvc). Поскольку управляемая транзакция аннотации определена в контексте корневого приложения, она не применяется к bean-компонентам в контексте сервлетов. Вы можете проверить это, удалив @Service и переместив определение bean-компонента в файл контекста сервлета - вы должны увидеть тот же результат.

Где, когда вы не используете компонентное сканирование - компонент определяется в XML контекста корневого приложения.

Исправление заключается в изменении тега компонентного сканирования в веб-слое, чтобы он включал только классы веб-слоя - либо с помощью другого базового пакета, либо с помощью фильтра включения / исключения. Добавьте еще один компонент сканирования в контексте корневого приложения для других компонентов.

Запросы могут работать, поскольку у вас может быть настроен OpenEntityManagerInViewInterceptor / Filter.

1 голос
/ 30 июля 2013

У меня та же проблема, и я ее решаю.

1-й, вы должны отделить свой контекст: компонентное сканирование на веб-уровне и уровень данных, например:

<!--in springcourt-servlet.xml -->
<context:component-scan base-package="com.springcourt.web" />

<!--in springcourt-data.xml -->
<context:component-scan base-package="com.springcourt.dao" />

2-е добавление в springcourt-data.xml

<aop:aspectj-autoproxy/>

Надеюсь, это будет полезно

1 голос
/ 14 октября 2011

Поскольку вы можете запрашивать БД через один и тот же компонент, ваш @Transactional работает, или вы часто получаете исключение (по крайней мере, в Hibernate).Скорее всего, в операции сохранения вы получите некоторое исключение времени выполнения, которое вызывает откат транзакции.Попытайтесь выяснить, что такое исключение, и перейдите оттуда.


Обновление

Чтобы проверить, было ли применено @Transactional, выведите трассировку стека изнутри метода.Если вы видите трассировку длинного стека с большим количеством транзакционных перехватчиков, это означает, что транзакционный аспект работает.

0 голосов
/ 09 мая 2016

Очень хорошей альтернативой тому, что у вас есть, является использование следующего: `

 @Configuration
 @EnableAspectJAutoProxy(proxyTargetClass=true)
 public class AppConfig {
     (...)
 }

Что вам нужно сделать, это ввести все в одной области видимости.Одним из способов является изменение ApplicationContext xml, как уже говорилось ранее, другой способ - использовать CGLIB, например, прокси Spring, чтобы вы получали прокси на основе подклассов и записывали свои реализации и определения bean-компонентов.

Дальнейшее чтение:

0 голосов
/ 15 октября 2011

Попробуйте это

  • Добавить проверку компонента контекста в spring-court-data.xml

      <context:component-scan base-package="com.springcourt" />
    
  • Тестировать сервис отдельно, СоздатьJUNIT Испытайте что-нибудь подобное

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations={"classpath:springcourt-data.xml"})
    @Transactional
    public class ReservationServiceImplTest()
    {
         @Autowired
         ReservationServiceImpl service;
    
         @Test
          public void validateContext()
          {
              Assert.assertNotNull(service); 
          }
    
          @Test
          @Rollback(false)
          public void save()
          {
             service.save(data);
          }
    
    }
    
...