TransactionRequiredException:Spring Data JPA没有进行任何事务

时间:2012-01-13 20:59:53

标签: java hibernate spring spring-data-jpa

looked around遇到类似问题但无法找到解决方法:

我有一个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中,它是自动连接并且有效。
  3. 有没有人遇到类似的问题,知道发生了什么事? 非常感谢您花时间阅读本文。希望这个问题的答案能够帮助其他人。

4 个答案:

答案 0 :(得分: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">

答案 1 :(得分:2)

  • 开始和提交事务是明确的。

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

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

而不是预期的Spring的代理(已经为你做过事务管理),你得到一个简单的对象,除了它之外什么都不知道是立即声明。

你需要做的是信任Spring 为你做管道工作,然后将bankRepository bean注入DatabaseManagerDAO(虽然我不是真的认为你需要DAO和Repository,因为这些术语的确意味着同样的事情:)

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

无需另外抽象。只需将它作为bean注入任何需要它的组件。

  • bankRepository应为@Autowired,但当我这样做时,我会null。但是,在this testcase中,它是自动连接并且有效。

如果it works您使用AbstractTransactionalJUnit4SpringContextTests运行测试,知道关于'bankRepository'bean,则自动装配它。在DatabaseManagerDAO中,我既看不到自动装配,也看不到bankRepository的设定者,事实上你是从工厂手动创建的。

编辑回答评论

您的XML配置中的jpa:repositories确实做了什么=&gt;它扫描包并为每个注释为@Repository或实现Repository接口的组件创建Spring bean。

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

@Service
public class DatabaseManagerDAO {

    @Autowired
    BankRepository bankRepository;
    ... 
}

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

同样,您案例中的DatabaseManagerDAO可能是一项服务(@Service),而不是DAO,但我会由您自行决定。

请注意,Spring也应加载DatabaseManagerDAO以使自动装配工作,因此当您使用时,请确保它具有一个Spring注释(@Service / @Component)包扫描它(例如<context:component-scan base-package="org.example"/>)。

答案 2 :(得分:2)

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

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

由于JPA需要PlatformTransactionManager而导致错误。

答案 3 :(得分:1)

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

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