1

四处寻找类似的问题 但找不到解决方案:

我有一个Spring Data JPA应用程序,每当我尝试进行交易时,我都会得到javax.persistence.TransactionRequiredException: no transaction is in progress.

我相信它与事务管理器或实体管理器工厂有关,但不能指望它。

上下文文件在这里(最新签入在这里),但这里是重要的部分:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSourceMySQL" />
    <property name="persistenceUnitName" value="spring-jpa" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="generateDdl" value="true" />
            <property name="showSql" value="true" />
            <property name="database" value="MYSQL" />
        </bean>
    </property>
</bean>

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

<bean id="dataSourceMySQL" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/dbname"/>
    <property name="username" value="user"/>
    <property name="password" value="pass"/>
</bean>

<jpa:repositories base-package="com.simplecash.dal.repository" />

这里有一个示例存储库,然后在此处创建了一个存储库工厂,我不确定是否需要...然后在此处使用它(第 34 行)。

public void populateWithTestData() {

    Bank bank = new Bank();
    bank.setName("ContentName");
    bank.setCode("ContentCode");

    RepositoryFactory.getEntityManager().getTransaction().begin();
    BankRepository bankRepository = RepositoryFactory.getRepository(BankRepository.class);
    bankRepository.save(bank);
    bankRepository.flush();
    RepositoryFactory.getEntityManager().getTransaction().commit();
}

上面有几件事是错误的,但我已经尝试修复它并且不能:

  1. 开始和提交事务是显式的。
  2. bankRepository应该是@Autowired,但是当我这样做时,我得到了null。但是,在这个测试用例中,它是自动装配的并且可以工作。

有没有人遇到过类似的问题并且知道发生了什么?非常感谢您花时间阅读本文。希望这个问题的答案能帮助其他人。

4

4 回答 4

3

此处提供的两个答案都提供了优点(使用注入来获取代理 bean 并使用事务注释),但是,我很确定要使注释驱动的事务正常工作(@Transactional),您需要将以下内容添加到您的 xml 配置:

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

还要确保在您的 beans-tag 中添加 tx-namespace:

<beans
  <!-- SNIP, other namespaces -->
xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="
  <!-- SNIP, other locations -->
  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
于 2012-01-14T08:52:22.663 回答
2

spring-batch组合and时我遇到了类似的问题spring-jpa。在我的批处理 XML 中,我有这一行:

<bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"/>

由于 JPA 需要PlatformTransactionManager.

于 2013-03-10T18:55:35.287 回答
2

我认为在您的设置中,事务由 JTA 管理,因此您不能显式启动/停止它们(即 em.getTransaction().begin() 将不起作用)。尝试通过 annotation 告诉 Spring 您希望某个方法成为(JTA 管理的)事务的一部分,例如:

@Transactional
public void populateWithTestData() {
   //...    
}
于 2012-01-13T21:51:21.703 回答
2
  • 开始和提交事务是显式的。

Spring 对您的存储库 bean(例如BankRepository)所做的事情,它围绕它创建一个代理,然后准备好注入其他协作者,在您的情况下是DatabaseManagerDAO. 但是,如果您像自己一样创建对象:

BankRepository bankRepository = RepositoryFactory.getRepository(BankRepository.class);

代替预期的 Spring 代理(已经为您进行事务管理),您将获得一个简单的对象,除了立即声明之外,它不知道任何事情。

相反,您需要做的是相信 Spring会为您做管道工作,只需将bankRepositorybean 注入到 a 中DatabaseManagerDAO(尽管我真的不认为您需要 DAO 和 Repository,因为这些术语的真正含义是相同的 :)

  • 这里是存储库工厂,我不确定是否需要...

不需要另一个抽象。只需将它作为 bean 注入到任何需要它的组件中。

  • bankRepository应该是@Autowired,但是当我这样做时,我得到了null。但是,在这个测试用例中,它是自动装配的并且可以工作。

在它工作的情况下,你运行你的测试AbstractTransactionalJUnit4SpringContextTests,它知道'bankRepository' bean,因此自动装配它。在您的DatabaseManagerDAO中,我看不到自动装配或设置器bankRepository,实际上您是从工厂手动创建的。

编辑回答评论

jpa:repositories的 XML 配置中真正执行的操作 => 它扫描包并为每个组件创建 Spring bean,这些组件要么被注释为@Repository要么实现Repository接口。

考虑到这一点,为了在您的存储库中使用BankRepository存储库,您应该做的DatabaseManagerDAO是注入它。您可以通过“自动装配”来做到这一点:

@Service
public class DatabaseManagerDAO {

    @Autowired
    BankRepository bankRepository;
    ... 
}

而不是通过您的工厂手动创建它。

同样,DatabaseManagerDAO在您的情况下,可能是服务 ( @Service),而不是DAO,但我将由您来决定。

请注意,a还应该由 Spring 加载,以便自动装配工作,因此在您对它进行打包扫描时(例如 ),请DatabaseManagerDAO确保它具有 Spring 注释之一(@Service/ )。@Component<context:component-scan base-package="org.example"/>

于 2012-01-14T06:17:44.750 回答