功能测试中的回滚事务在另一个Spring环境中开始

时间:2015-01-16 03:06:50

标签: java spring hibernate transactions rollback

实施功能测试。为了避免数据损坏,我需要在执行后回滚每个测试。这是非常简单的任务 - 只需在测试中标记rollback = true。但是如果我用另一个弹簧上下文启动另一个模块并且第一个模块以某种方式与它交互(例如发送jms消息而第二个将它保存到同一个DB),则回滚不适用于第二个上下文。如何回滚第二个模块?

    @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:/my-service-context.xml")
@Transactional(value = "myTransactionManager")
public class ParserServiceTest {

    protected Logger l = LoggerFactory.getLogger(getClass());

    @Autowired
    @Qualifier(value = "earMessageDaoBean")
    EARMessageDao dao;

    @Autowired
    @Qualifier(value = "myParserService")
    ParserService service;

    @Test
    @Rollback(value = true)
    public void testExecute() throws Exception {
        service.execute("fff", "ttt");
        EARMessage byId = dao.findById(1L);
        assertNotNull(byId);
        assertEquals("fff", byId.getFrom());
        assertEquals("ttt", byId.getTo());
        l.info("{}", byId);
    }
}

如果我看一下db,我会看到没有数据,这很好

但如果我要添加另一个模块

    @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:/my-service-context.xml")
@Transactional(value = "myTransactionManager")
public class ParserServiceTest {

    protected Logger l = LoggerFactory.getLogger(getClass());

    ClassPathXmlApplicationContext context2;

    @Before
    public void setUp() throws Exception {
        context2 = new ClassPathXmlApplicationContext(
                "my-service-context2.xml"
        );
    }

    @Autowired
    @Qualifier(value = "earMessageDaoBean")
    EARMessageDao dao;

    @Autowired
    @Qualifier(value = "myParserService")
    ParserService service;

    @Test
    @Rollback(value = true)
    public void testExecute() throws Exception {
        service.execute("fff", "ttt");
        EARMessage byId = dao.findById(1L);
        assertNotNull(byId);
        assertEquals("fff", byId.getFrom());
        assertEquals("ttt", byId.getTo());
        l.info("{}", byId);
// theoretically there could be interaction with service2 via JMS
        MyParserService2 service2 = (MyParserService2) context2.getBean("myParserService2");
        service2.execute("FFF", "TTT");
    }
}

由servie2添加的数据不会被回滚。

我可以在测试上下文中获取EntityManager TransactionManager,但由于事务已经提交,我无法回滚它们。 我可以在第二个模块中添加一些标记并在测试中以某种方式标记它,但现在已经知道该做什么

UPDATE 这里有服务和上下文配置,以便更好地理解:

    @Service(value = "myParserService")
@Transactional(value = "myTransactionManager")
public class ParserService {

    protected Logger l = LoggerFactory.getLogger(getClass());

    @Autowired
    @Qualifier(value = "earMessageDaoBean")
    EARMessageDao dao;

    public void execute(String from, String to) {
        l.info("-------started service 1---------");
        EARMessage message = new EARMessage();
        message.setFrom(from);
        message.setTo(to);
        message.setProcessingDate(new DateTime());
        dao.persist(message);
        l.info("-------ended  service 1---------");
    }
}


    @Service(value = "myParserService2")
@Transactional(value = "myTransactionManager")
public class MyParserService2 {

    protected Logger l = LoggerFactory.getLogger(getClass());

    @Autowired
    @Qualifier(value = "earMessageDaoBean")
    EARMessageDao dao;

    public void execute(String from, String to) {
        l.info("-------started service 2---------");
        EARMessage message = new EARMessage();
        message.setFrom("666" + from);
        message.setTo("666" + to);
        message.setProcessingDate(new DateTime());
        dao.persist(message);
        l.info("-------ended  service 2---------");
    }
}

我的服务-context.xml中

   <context:annotation-config/>
<context:component-scan base-package="com.dimas.tutorial.hibernate.simple"/>

<import resource="classpath:/my-service-config.xml"/>
<import resource="classpath:/my-data-source.xml"/>
<import resource="classpath:/my-entity-manager.xml"/>

<jdbc:initialize-database data-source="${dataSource.name}">
    <jdbc:script location="classpath:/sql/my-schema.sql"/>
</jdbc:initialize-database>

我的服务-context2.xml

   <context:annotation-config/>
    <context:component-scan base-package="com.dimas.tutorial.hibernate.simple"/>

    <import resource="classpath:/my-service-config.xml"/>
    <import resource="classpath:/my-data-source.xml"/>
    <import resource="classpath:/my-entity-manager.xml"/>

    <jdbc:initialize-database data-source="${dataSource.name}">
        <jdbc:script location="classpath:/sql/my-schema.sql"/>
    </jdbc:initialize-database>

UPDATE2:添加了实体管理器配置

<bean id="valettaEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="MyPersistence"/>
        <property name="packagesToScan" value="com.dimas.tutorial.hibernate.simple.domain"/>
        <property name="dataSource" ref="${dataSource.name}"/>
        <property name="jpaVendorAdapter" ref="hibernateVendor"/>
        <property name="jpaPropertyMap" ref="jpaPropertyMap"/>
    </bean>

    <util:map id="jpaPropertyMap">
        <entry key="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
        <entry key="hibernate.default_schema" value="public"/>
        <entry key="hibernate.show_sql" value="false"/>
        <entry key="hibernate.format_sql" value="false"/>
        <entry key="hibernate.cache.use_second_level_cache" value="false"/>
        <entry key="hibernate.max_fetch_depth" value="3"/>
        <entry key="hibernate.jdbc.fetch_size" value="50"/>
        <entry key="hibernate.jdbc.batch_size" value="10"/>
    </util:map>

    <bean id="hibernateVendor" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="showSql" value="false"/>
    </bean>

    <bean id="myTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="valettaEntityManagerFactory"/>
    </bean>

    <bean id="valettaTransactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="myTransactionManager"/>
    </bean>

    <context:annotation-config/>
    <tx:annotation-driven transaction-manager="myTransactionManager"/>

1 个答案:

答案 0 :(得分:0)

使用您的服务所需的传播 例如 第一笔交易:

@Transactional(value = "myTransactionManager")
  public class ParserServiceTest {

加入要求交易:

 @Transactional(value = "myTransactionManager", propagation=Propagation.REQUIRED)
    public class ParserService {

加入要求交易:

@Transactional(value = "myTransactionManager", propagation=Propagation.REQUIRED)
public class MyParserService2 {

<强> PROPAGATION_REQUIRED:     Spring REQUIRED行为意味着如果当前bean方法执行上下文中已经打开的事务,将使用相同的事务。如果不存在,则创建一个新的。     简而言之,这意味着如果内部(第二个事务)方法导致事务回滚,外部(第一个事务)方法将无法提交,并且还将回滚事务