声明式事务 (@Transactional) 在 Spring 中不适用于 @Repository [英] Declarative transactions (@Transactional) doesn't work with @Repository in Spring

查看:31
本文介绍了声明式事务 (@Transactional) 在 Spring 中不适用于 @Repository的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 Spring、JPA 和嵌入式 H2 数据库制作简单的应用程序.最近我遇到了声明式事务的这个奇怪问题.如果我使用 @Repository 注释自动装配我的 DAO,他们就不会提交.更具体地说,我在刷新时遇到异常:

I'm trying to make simple application using Spring, JPA and embedded H2 database. Recently I've come across this strange issue with declarative transactions. They just doesn't commit if I autowire my DAO with @Repository annotation. More specifically I get exception on flush:

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

这是我的设置:

<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;
    }
}

DAO

@Repository
public class JpaDao {

    @PersistenceContext
    private EntityManager em;

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

database.xml(包含在根 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 ":)";
    }
}

现在是有趣的部分.如果我从 DAO 中删除 @Repository 注释并在 database.xml 中明确指定它,则一切正常.

And now the interesting part. If I remove @Repository annotation from DAO and specify it explicitly in database.xml, everything works fine.

将另一个 <tx:annotation-driven/> 放入 spring servlet 配置可以解决问题,但为什么呢?

Putting another <tx:annotation-driven /> into spring servlet config fixes the problem, but why?

推荐答案

可能是因为 spring-servlet.xml 中的 component-scan 也包含了你的 DAO 类在其扫描过程中,因此在其应用程序上下文(而不是数据库"上下文)中为它们创建实例......这样当您的 Web 从 Web 控制器访问这些 DAO 时,它正在访问它们的非事务版本(除非您添加tx:annotation-driven 标签).

Probably because the component-scan in your spring-servlet.xml is also including your DAO classes in its scanning and therefore creating instances for them in its application context (not the "database" one)... so that when your web accesses these DAOs from web controllers, it is accessing non-transactional versions of them (unless you add that tx:annotation-driven tag).

因此,添加该标签实际上是一个糟糕的解决方案,因为它仍然会在错误的应用程序上下文中创建您的 DAO 实例:最好为您的 web 层组件创建创建一个更具体的 base-package 配置.

Therefore, adding that tag is in fact a bad solution because it still creates your DAO instances in the wrong application context: better create a more specific base-packageconfiguration for your web layer component creation.

我遇到了同样的问题,因为我认为我的 spring-servlet.xml 中的 <context:include-filter> 只负责扫描 @Controller 类...但没有:-(

I had this same problem because I thought a <context:include-filter> in my spring-servlet.xml was taking care of only scanning @Controller classes... but no :-(

这篇关于声明式事务 (@Transactional) 在 Spring 中不适用于 @Repository的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆