【问题标题】:Issue with @Transactional annotations in Spring JPASpring JPA 中的@Transactional 注释问题
【发布时间】:2013-01-06 02:03:35
【问题描述】:

我对交易中的交易存有疑问。对于背景,我有一个 School 实体对象,它映射了一组学生实体对象。我正在使用 Spring Data JPA,它负责所有的 crud 操作。我有一个 SchoolManagementService 类,它在类级别设置了 @Transactional(readonly=true) ,并且对于所有更新方法,我在它们上使用了 @Transactional 。 在我的 SchoolManagementService 类中,我有一个方法 deleteStudents(List),我已将其标记为 @Transactional。在这种方法中,我一次又一次地调用 StudentsRepository.delete(studentId)。我想确保如果任何删除失败,那么事务应该回滚该检查的异常。我正在尝试使用我的 spring junit 测试用例对此进行测试(我没有使用默认的 rollback=true 或@rollback(true),因为我希望回滚它,因为我在存储库删除方法中遇到了一些运行时异常。

@RunWith(SpringJUnit4ClassRunner.class)   
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class})   
@ContextConfiguration(locations = {"classpath:PPLRepository-context.xml"})
public class TestClass{


@Test
@Transactional
public void testDeleteStudents(){
StudentManagementService.delete(randomList)
}

使用此测试用例,它会删除除最后一条之外的所有记录。理想情况下,它应该回滚并且不应该删除任何条目。

这是我的带有 TransactionMangaer 配置的 sprin 设置文件

<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init"
            destroy-method="close">
            <property name="forceShutdown" value="true" />
            <property name="startupTransactionService" value="true" />
            <property name="transactionTimeout" value="1000" />
        </bean>

        <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp" />
        <!-- Configure the Spring framework to use JTA transactions from Atomikos -->
        <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
            <property name="transactionManager" ref="atomikosTransactionManager" />
            <property name="userTransaction" ref="atomikosUserTransaction" />
            <property name="transactionSynchronizationName" value="SYNCHRONIZATION_ON_ACTUAL_TRANSACTION" />
        </bean>

            <!-- EntityManager Factory that brings together the persistence unit, datasource, and JPA Vendor -->
            <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="PPL_GMR">
                <property name="dataSource" ref="PPL_GMRDS"></property>
                <property name="persistenceUnitName" value="PPL_GMR"/>
                <property name="persistenceXmlLocation" value="classpath:META-INF/PPL-persistence.xml"/>
                <property name="jpaVendorAdapter" ref="PPL_GMRJPAVendorAdapter"/>
                    <property name="jpaPropertyMap">
                        <map>
                                    <entry key="hibernate.transaction.manager_lookup_class" value="com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup"/> 
                                    <entry key="hibernate.connection.release_mode" value="on_close"/>
                                    <entry key="hibernate.default_schema" value="${PPL.schema}"/>
                        </map>
                    </property>
</bean>

有人能指出我对交易的理解哪里错了吗?无论我从 API 中读到什么,我的印象是,如果某个方法在服务层是 @Transactional,并且如果它调用 Spring Data JPA 存储库的多个 @Transactional 方法,那么如果我遇到任何运行时异常,那么所有事务都应该回滚. 我什至尝试简单地创建一个测试用例方法,如下所示:

@Test
@Transactional
public void testDeleteStudents(){
StudentRepository.delete(1);
StudentRepository.delete(2);// 2 id is not present so I will get a runtime exception.
}

尽管在此方法上保留了@Rollback(true/false),但此方法会从数据库中删除 id 1 Student。我认为这个测试用例方法中的 @Transactional 将在这里创建一个新事务,并且 StudentRepository 中的所有事务删除方法都将在同一个事务中运行。除非没有抛出运行时异常,否则不会提交学生数据。

请帮助我更好地了解交易,因为我是新手。我正在使用带有 Oracle 数据库的 Spring Data JPA。

提前致谢。

【问题讨论】:

  • 嗨,有人可以帮我解决这个问题吗...这个问题让我很生气..

标签: spring jpa junit4 spring-transactions transactional


【解决方案1】:

我认为默认行为是(即使您在测试类中没有它)

@TransactionConfiguration(defaultRollback = true)

所以它会在您的测试结束时执行回滚。因此,hibernate session 不会与数据库同步,也不会向数据库发出查询 SQL。

您有两种可能性。要么指定

@TransactionConfiguration(defaultRollback = false)

或将实体管理器注入您的测试并调用

@PersistenceContext
protected EntityManager em;

/**
 * Simulates new transaction (empties Entity Manager cache).
 */
public void simulateNewTransaction() {
    em.flush();
    em.clear();
}

这将强制休眠将所有查询发送到数据库。请注意,这将解决您删除不存在实体的问题,但它的行为与新交易不完全相同,例如当您缺少外键时,它不会抛出任何东西(这是可以预测的。

您可以使用它来检查 em.find(class, id) 返回的实体的内容,并检查您的关系映射,而无需提交事务。

【讨论】:

    猜你喜欢
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    • 2015-04-16
    • 1970-01-01
    • 2014-12-24
    • 2019-06-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多