私たちは、一連のスレッドがデッドロックし、サーバーが動作しなくなった生産インシデントが発生しました。試して調べるために、私はバネのトランザクションの伝播が異なるいくつかのものをテストしました。間違いがなければREQUIRES_NEW伝播は既存のトランザクションが全くなければ2つの接続を開始します。これは正しいです??私はグーグルを試みたが、これに関する情報は見つからなかった。@Transactional(propagation = Propagation.REQUIRES_NEW)は2つのトランザクションを開きますか?
私はテストを行いました。ここではサンプルクラスです:
ここ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を非常に高い値に設定しても、このメソッドを実行するために十分なスレッドが待機していても、すべてが1つの接続を占有して2番目の接続を待つことができるからです。
私は間違ったことをしましたか?私は何かを誤解したことがありますか?
ご協力いただきありがとうございます。ありがとう!
いいえ、2つの接続を開くことはできません。 'REQUIRES_NEW'のために、あなたのテストでトランザクションが開かれ、サービスで新しいものが1つ開かれたため、あなたのテストでは実行されます。 –
なぜ私はテストでオープンしましたか?それを避ける方法はありますか?また、特定のメソッドがトランザクション内にあるかどうかを確認するために、新しいException()。printStackTrace()を追加し、TransactionInterceptorを探します。これは、テストメソッドに追加するときには見えません。 – user3306066
'AbstractTransactionalJUnit4SpringContextTests'は、classnameの' Transactional'部分が理由のためにそこにあると思いますか?トランザクションを処理するには、さらに多くの方法があります。トランザクションを手動で開始/停止する 'TransactionalTestExecutionListener'によって行われるテストです。テストをトランザクションにしたくない場合は、 'AbstractTransactionalJUnit4SpringContextTests'を拡張しないでください。 –