声明式事务(@Transactional)在 Spring 中不能与 @Repository 一起使用

发布于 2024-12-29 14:12:23 字数 3074 浏览 1 评论 0原文

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

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

这是我的设置:

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

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 中显式指定它,则一切正常。

更新

将另一个 放入 spring servlet 配置中可以解决问题,但为什么呢?

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

Here is my setup:

persistence.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

@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 (included from root spring context)

<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

@Controller
public class HomeController {

    @Inject
    JpaDao dao;

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

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

Update

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

清秋悲枫 2025-01-05 14:12:23

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

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

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

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).

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.

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 :-(

ら栖息 2025-01-05 14:12:23

只是一种猜测,但您不需要注册自己的 PersistenceAnnotationBeanPostProcessor,因为 会自动注册一个。两者有可能互相干扰。

不过,就像我说的,这只是一种预感。

Just a guess, but you don't need to register your own PersistenceAnnotationBeanPostProcessor, since <context:component-scan> registers one automatically. It's possible that the two are interfering with one another.

Like I said, though, just a hunch.

裂开嘴轻声笑有多痛 2025-01-05 14:12:23

@Transactional 注解可以放在接口定义、接口上的方法、类定义或类上的公共方法之前。但是,请注意,仅存在 @Transactional 注释并不足以实际打开事务行为 - @Transactional 注释只是可以由具有@Transactional 意识并且可以使用元数据来配置具有事务行为的适当bean 的东西。在上面的示例中, 元素的存在开启了事务行为。

来自 spring 文档 http://static.springsource.org/spring/ docs/2.0.8/reference/transaction.html

The @Transactional annotation may be placed before an interface definition, a method on an interface, a class definition, or a public method on a class. However, please note that the mere presence of the @Transactional annotation is not enough to actually turn on the transactional behavior - the @Transactional annotation is simply metadata that can be consumed by something that is @Transactional-aware and that can use the metadata to configure the appropriate beans with transactional behavior. In the case of the above example, it is the presence of the <tx:annotation-driven/> element that switches on the transactional behavior.

from spring doc http://static.springsource.org/spring/docs/2.0.8/reference/transaction.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文