声明式事务 (@Transactional) 在 Spring 中不适用于 @Repository [英] Declarative transactions (@Transactional) doesn't work with @Repository in Spring
问题描述
我正在尝试使用 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-package
configuration 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屋!