【问题标题】:TransactionRequiredException: no transaction is in progress with Spring Data JPATransactionRequiredException:Spring Data JPA 没有正在进行的事务
【发布时间】:2012-02-10 01:04:58
【问题描述】:

lookedaround 遇到类似问题,但找不到解决方案:

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

我认为它与事务管理器或实体管理器工厂有关,但无法确定。

上下文文件为here(最新签入为here),但重要的部分如下:

<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" />

一个示例存储库是here,然后创建了一个存储库工厂here,我不确定是否需要... 然后使用它here(第 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。但是,在 this testcase 中,它是 Autowired 并且可以正常工作。

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

【问题讨论】:

    标签: java hibernate spring spring-data-jpa


    【解决方案1】:

    此处提供的两个答案都提供了优点(使用注入来获取代理 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">
    

    【讨论】:

      【解决方案2】:

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

      @Transactional
      public void populateWithTestData() {
         //...    
      }
      

      【讨论】:

      • 我尝试添加@Transactional 注释,但没有奏效。我现在拥有的代码(带有显式 begincommit)可以工作,但我认为存储库的 save 已经具有 @Transactional 属性,我不一定需要它在我的函数中(虽然我想我可以添加它)。我认为问题在于我注入EntityManagerFactory bean 的方式或应用程序上下文的xml文件中缺少某些内容..
      【解决方案3】:
      • 开始和提交事务是显式的。

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

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

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

      你需要做的是信任 Spring 为你做管道,只需将 bankRepository bean 注入 DatabaseManagerDAO (虽然我真的不认为你需要两者DAO 和 Repository,因为这些术语的真正含义是一样的 :)

      • Repository Factory 在这里,我不确定是否需要...

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

      • bankRepository 应该是 @Autowired,但是当我这样做时,我会得到 null。但是,在 this testcase 中,它是 Autowired 并且可以正常工作。

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

      编辑回答 cmets

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

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

      @Service
      public class DatabaseManagerDAO {
      
          @Autowired
          BankRepository bankRepository;
          ... 
      }
      

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

      同样,在您的情况下,DatabaseManagerDAO 可能是一项服务 (@Service),而不是 DAO,但我会让您自己决定。

      注意,DatabaseManagerDAO 也应该由 Spring 加载,以便自动装配工作,所以在你打包扫描它时确保它具有 Spring 注释之一(@Service / @Component)(例如@ 987654346@).

      【讨论】:

      • “我看不到 bankRepository 的自动装配和设置器,实际上你是从工厂手动创建的”。我必须在这里遗漏一些基本的东西..你能给我一个类和xml的例子,这样我就可以注入BankRepository的实例吗?
      【解决方案4】:

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

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

      由于 JPA 需要 PlatformTransactionManager,因此导致错误。

      【讨论】:

        猜你喜欢
        • 2015-05-04
        • 2015-05-11
        • 2016-03-26
        • 2017-12-30
        • 2013-12-09
        • 2013-03-23
        • 2010-12-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多