首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >@Transactional(propagation=Propagation.REQUIRES_NEW)打开两个事务?

@Transactional(propagation=Propagation.REQUIRES_NEW)打开两个事务?
EN

Stack Overflow用户
提问于 2017-06-16 16:37:13
回答 1查看 2.2K关注 0票数 2

我们有一个生产事件,导致一堆线程死锁,服务器停止工作。为了尝试和研究,我用不同的spring事务传播测试了一些东西,如果我没有弄错的话,如果根本没有现有的事务,REQUIRES_NEW传播将启动两个连接。这样做对吗?我试着用谷歌搜索,但没有找到关于这方面的信息。

我做了个测试。下面是一个示例类:

代码语言:javascript
复制
package test;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class TheService {

    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public void doSomething() {
        System.out.println("Here I am doing something.");
    }
}

下面是我做的单元测试:

代码语言:javascript
复制
package test;

import javax.annotation.Resource;

import org.junit.Test;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;

@ContextConfiguration(locations = {"classpath:test.xml"})
public class TheServiceTest extends AbstractTransactionalJUnit4SpringContextTests {

    @Resource
    private TheService theService;

    @Test
    public void test() {
        theService.doSomething();
    }

}

最后但并非最不重要的是,下面是我的测试xml:

代码语言:javascript
复制
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx" 
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.1.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"
    default-autowire="byName">

    <context:component-scan base-package="test" />

    <tx:annotation-driven transaction-manager="transactionManager" />

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

    <bean id="operator.entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="operatorPersistenceUnit" />
        <property name="dataSource" ref="operator.dataSource" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="false" />
                <property name="generateDdl" value="true" />
                <property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" />
            </bean>
        </property>
    </bean>

    <bean id="operator.dataSource" class="org.apache.commons.dbcp.BasicDataSource"  destroy-method="close">
        <property name="driverClassName" value="org.h2.Driver" />
        <property name="url" value="jdbc:h2:mem:operator" />
        <property name="username" value="sa" />
        <property name="password" value="" />
        <property name="maxActive" value="1" /> <!-- NOTE -->
    </bean>
</beans>

我想为一个方法使用REQUIRES_NEW的原因是,不能从该方法中获得任何脏读取,这一点至关重要,而且它既可以在另一个事务内部执行,也可以在外部执行。

如果我将maxActive属性保持为1,则此测试将死锁,并且永远不会打印任何内容。但是,如果我将其更改为2,测试将通过。

这是一个令人担忧的问题,因为即使我将maxActive设置为一个更高的值,有足够多的线程等待执行此方法,它们最终也可能各自占用一个连接并等待第二个连接。

我做错什么了吗?我是不是误解了什么?

感谢大家的帮助!谢谢!

EN

回答 1

Stack Overflow用户

发布于 2017-06-16 17:36:46

这与默认情况下不会打开2个连接的propagation=REQUIRES_NEW无关。问题是您正在扩展AbstractTransactionalJUnit4SpringContextTests

正如您所看到的,您的测试用例扩展了AbstractTransactionalJUnit4SpringContextTests,即@Transactional。此测试事务由TransactionalTestExecutionListener管理。

因此,当您开始测试时,在执行测试方法之前,测试框架会启动一个事务。接下来,调用您的服务,该服务将启动另一个事务,这是由于使用@Transactional(propagation=REQUIRES_NEW)进行了注释。

修复非常简单,不需要扩展AbstractTransactionalJUnit4SpringContextTests,只需使用@RunWith(SpringRunner.class)注释您的类。

代码语言:javascript
复制
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = {"classpath:test.xml"})
public class TheServiceTest { ... }
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44584608

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档