@Transactional不会打开另一个事务

时间:2017-05-28 13:32:21

标签: java spring hibernate

我正在尝试使用@Transactional Spring framework的方法打开方法的多个交易 由于某种原因,它会抛出java.lang.IllegalStateException : Transaction already active

我的方法

@Transactional
Public void foo(Entity e){

      entityManager.merge(e);

      entityManager.getTransaction().begin();

      entityManager.getTransaction().commit();

  }

知道如何在不收到错误的情况下打开多个交易吗?

1 个答案:

答案 0 :(得分:2)

我认为你可能会混淆Spring @Transactional注释的含义。当您使用该注释时,您要求Spring使用事务语义来丰富您的方法调用。

您可能需要查看TransactionAspectSupport类,更具体地说是方法invokeWithinTransaction,这是您的交易方法发生所有魔法的地方。

您将看到在调用代码之前,创建了一个新事务,然后执行了代码,之后,发生了提交或回滚。换句话说,Spring的方面控制着你的交易。

所有这些魔法需要一些配置才能实现:你需要确保Spring找到你的@Transactional方法并丰富它们。为此,您需要添加一段配置:

<tx:annotation-driven/>

当然,您需要定义可由事务方法使用的事务管理器。看来你正在使用JPA,所以JpaTransactionManager在这种情况下有意义:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="database" value="POSTGRESQL"/>
            <property name="showSql" value="true"/>
        </bean>
    </property>
    <property name="jpaDialect">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect">
            <property name="prepareConnection" value="true"/>
        </bean>
    </property>
    <property name="persistenceUnitName" value="test-api"/>
    <property name="packagesToScan">
        <list>
            <value>com.company.humanresources</value>
        </list>
    </property>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <constructor-arg name="emf" ref="entityManagerFactory"/>
</bean>

最后,如果您想获得当前交易所使用的实体经理的访问权限,您可以执行以下操作:

@PersistenceUnit(unitName = "test-api")
EntityManagerFactory emf;

@Transactional
public Department addDepartment(String name) {
   EntityManager em = EntityManagerFactoryUtils.getTransactionalEntityManager(emf);
   Department department = new Department();
   department.setName(name);
   em.persist(department);
   return department;
});

Spring将再次控制事务方法的事务语义。您还必须考虑到默认的Spring行为仅适用于公共方法。