2017-06-16 35 views
1

我們有一個生產事件導致一堆線程死鎖並且服務器停止工作。爲了嘗試和調查,我測試了一些具有不同春季交易傳播的東西,如果我沒有弄錯,那麼REQUIRES_NEW傳播將在沒有現有交易的情況下啓動兩個連接。它是否正確??我嘗試了谷歌搜索,但沒有找到關於此的信息。@Transactional(propagation = Propagation.REQUIRES_NEW)打開兩個事務?

我做了一個測試。下面是一個示例類:

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."); 
    } 
} 

這裏是我做單元測試:

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:

<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設置爲更高的值,並且有足夠的線程等待執行此方法,它們最終都會佔用一個連接並等待第二個連接。

我做錯了什麼?我誤解了任何東西嗎?

我感謝任何幫助!謝謝!

+0

不,它沒有打開2個連接。它在你的測試中有效,因爲1是你的測試打開的(它是事務性的)並且在你的服務中有一個新的,因爲'REQUIRES_NEW' .. –

+0

爲什麼我的測試打開了一個?有沒有辦法避免這種情況?另外,有時爲了查看某個方法是否在事務中,我添加了一個「新的Exception()。printStackTrace()',並且查找了TransactionInterceptor。這個,我在添加測試方法時看不到。 – user3306066

+0

你認爲'AbstractTransactionalJUnit4SpringContextTests'確實......那個'Transactional'部分的類名是有原因的。有更多的方式來處理交易。對於通過手動啓動/停止事務的'TransactionalTestExecutionListener'完成的測試。如果你不想讓你的測試成爲事務性的,不要擴展'AbstractTransactionalJUnit4SpringContextTests'。 –

回答

2

它與propagation=REQUIRES_NEW無關,默認情況下不會打開2個連接。問題是你正在延伸AbstractTransactionalJUnit4SpringContextTests

由於您的測試用例擴展了AbstractTransactionalJUnit4SpringContextTests,您可以看到它是@Transactional。該交易用於測試,由TransactionalTestExecutionListener管理。

因此,當測試框架啓動一個事務之前,在測試方法執行之前開始測試時會發生什麼。接下來,由於使用@Transactional(propagation=REQUIRES_NEW)進行註釋,您將調用啓動另一個交易的服務。

該修復很容易不延伸AbstractTransactionalJUnit4SpringContextTests,只需用@RunWith(SpringRunner.class)註釋您的班級。

@RunWith(SpringRunner.class) 
@ContextConfiguration(locations = {"classpath:test.xml"}) 
public class TheServiceTest { ... } 
+0

你是對的。我的錯。謝謝你的幫助,好的先生! – user3306066

相關問題