8

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

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(包含在根 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 中明确指定它,一切正常。

更新

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

4

3 回答 3

5

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

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

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

于 2012-06-03T10:11:57.213 回答
0

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

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

于 2012-01-29T11:31:38.623 回答
0

@Transactional注释可以放在接口定义、接口上的方法、类定义或类上的公共方法之前。但是,请注意,仅仅存在@Transactional注解并不足以真正打开事务行为——@Transactional注解只是元数据,可以被感知的东西消费,@Transactional并且可以使用元数据来配置具有事务性的适当 bean行为。在上面的例子中,是<tx:annotation-driven/>元素的存在开启了事务行为。

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

于 2012-01-29T11:23:25.873 回答