Декларативные транзакции (@Transactional) не работают с @Repository в Spring

Я пытаюсь создать простое приложение, используя Spring, JPA и встроенную базу данных H2. Недавно я столкнулся с этой странной проблемой с декларативными транзакциями. Они просто не фиксируются, если я автоматически связываю свой DAO с аннотацией @Repository. В частности, я получаю исключение при сбросе:

javax.persistence.TransactionRequiredException: 
Exception Description: No transaction is currently active

Вот моя установка:

постоянство.xml

<persistence-unit name="schedulePU" transaction-type="RESOURCE_LOCAL">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
        <property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
        <property name="javax.persistence.jdbc.url" value="jdbc:h2:~/scheduleDB" />
        <property name="javax.persistence.jdbc.user" value="sa" />
        <property name="javax.persistence.jdbc.password" value="" />
        <property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.H2Platform" />
        <property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
        <property name="eclipselink.logging.level" value="FINE"/>
    </properties>
</persistence-unit>

Организация

@Entity
@Table(name = "Professors")
public class Professor {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String name;

    public Professor() { }

    public Professor(String name) {
        this.name = name;
    }
}

ДАО

@Repository
public class JpaDao {

    @PersistenceContext
    private EntityManager em;

    @Transactional
    public void addProfessor(Professor professor) {
        em.persist(professor);
        em.flush();
    }
}

database.xml (включен из контекста root spring)

<beans>
    <context:component-scan base-package="com.spybot.schedule.dao" />

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

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="schedulePU" />
    </bean>

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

    <tx:annotation-driven transaction-manager="transactionManager" />
</beans>

Контроллер

@Controller
public class HomeController {

    @Inject
    JpaDao dao;

    @RequestMapping("/add")
    public @ResponseBody String add(String name) {
        Professor p = new Professor(name);
        dao.addProfessor(p);
        return ":)";
    }
}

А теперь самое интересное. Если я удалю аннотацию @Repository из DAO и укажу ее явно в файле database.xml, все будет работать нормально.

Обновлять

Добавление еще одного <tx:annotation-driven /> в конфигурацию spring servlet решает проблему, но почему?


person SpyBot    schedule 29.01.2012    source источник
comment
Попробуйте обменять @Inject на @Autowired   -  person beerbajay    schedule 29.01.2012
comment
‹context:component-scan base-package.... установлен правильно   -  person baba.kabira    schedule 29.01.2012
comment
@beerbajay пытался, тот же результат.   -  person SpyBot    schedule 29.01.2012
comment
Очень полезно, спасибо. Я боролся с подобной проблемой в течение двух дней, и перемещение <tx:annotation-driven/> в основной контекст тоже сработало для меня. Спасибо.   -  person Julius    schedule 19.07.2012


Ответы (3)


Вероятно, потому, что component-scan в вашем spring-servlet.xml также включает ваши классы DAO в свое сканирование и, следовательно, создает экземпляры для них в контексте своего приложения (а не в «базе данных»)... так что, когда ваша сеть обращается к этим DAO из веб-контроллеров, она обращается к их нетранзакционным версиям (если вы не добавите тег tx:annotation-driven).

Таким образом, добавление этого тега на самом деле является плохим решением, поскольку оно по-прежнему создает экземпляры DAO в неправильном контексте приложения: лучше создать более конкретную конфигурацию base-package для создания компонента веб-слоя.

У меня была такая же проблема, потому что я думал, что <context:include-filter> в моем spring-servlet.xml заботится только о сканировании @Controller классов... но нет :-(

person Daniel Fernández    schedule 03.06.2012

Всего лишь предположение, но вам не нужно регистрировать собственный PersistenceAnnotationBeanPostProcessor, так как <context:component-scan> регистрирует его автоматически. Возможно, они мешают друг другу.

Но, как я уже сказал, просто предчувствие.

person skaffman    schedule 29.01.2012

Аннотация @Transactional может быть помещена перед определением интерфейса, методом интерфейса, определением класса или общедоступным методом класса. Однако обратите внимание, что простого присутствия аннотации @Transactional недостаточно, чтобы фактически включить транзакционное поведение — аннотация @Transactional — это просто метаданные, которые могут использоваться чем-то, что поддерживает @Transactional, и может использовать метаданные для настройки соответствующих bean-компоненты с транзакционным поведением. В приведенном выше примере наличие элемента <tx:annotation-driven/> включает транзакционное поведение.

из весеннего документа http://static.springsource.org/spring/docs/2.0.8/reference/transaction.html

person Ramesh Kotha    schedule 29.01.2012
comment
Вы действительно хотите процитировать документы Spring из версии 2.0.8? - person skaffman; 29.01.2012
comment
Вы хоть читали вопрос? У меня было <tx:anotation-driven /> в моем контексте приложения. Я спрашиваю, почему добавление его в контекст сервлета решает проблему. - person SpyBot; 29.01.2012