私はその後、私はテストに100のサブスレッドでテストする必要があり、ターゲットメソッドを呼び出し、試験方法では、私が最初にMySQLのDBに保存されなければならないいくつかのテストデータを用意し、春ブーツ・テストとJUnitテストを書きましたターゲットメソッドが同時実行でうまく機能するかどうか。この試験方法は、次のようになります。
public class SysCodeRuleServiceImplTest extends BaseServiceTest {
@Autowired
private SysCodeRuleService sysCodeRuleService;
@Autowired
private SysCodeRuleDtlService sysCodeRuleDtlService;
private final String codeRuleNo = "sdkfjks443";
@Test
public void testCreateSheetIdWithoutUniformedSerial_2() throws InterruptedException {
//------ prepare test data start-----------
SysCodeRule sysCodeRule = new SysCodeRule();
sysCodeRule.setCodeRuleNo(codeRuleNo);
sysCodeRule.setIfDateCode(1);
sysCodeRule.setPadChar("0");
sysCodeRule.setSerialDigits(6);
sysCodeRule.setResetMode(1);
sysCodeRule.setIfUniteSerial(0);
sysCodeRule.setIfCache(0);
sysCodeRule.setConstValue("PETREL");
sysCodeRule.setStatus(1);
sysCodeRule.setName(codeRuleNo);
sysCodeRule.setCurSerialNo("0");
sysCodeRule.setCurSerialDate(new Date());
sysCodeRule.setCreateTime(new Date());
sysCodeRule.setCreator("自动");
sysCodeRule.setDateCutBeginPosition(3);
sysCodeRule.setDateCutEndPosition(8);
boolean insertSysCodeRuleSucc = sysCodeRuleService.insert(sysCodeRule);
assertThat(TestMessageConstants.PREPARE_TEST_DATA_FAILED, insertSysCodeRuleSucc);
assertThat("", sysCodeRule.getId(), notNullValue());
SysCodeRuleDtl sysCodeRuleDtl1 = new SysCodeRuleDtl();
sysCodeRuleDtl1.setSysCodeId(sysCodeRule.getId() + "");
sysCodeRuleDtl1.setOrderNo(1);
sysCodeRuleDtl1.setFieldValue("locno");
sysCodeRuleDtl1.setCutEndPosition(0);
sysCodeRuleDtl1.setCutBeginPosition(0);
sysCodeRuleDtl1.setCreateTime(new Date());
sysCodeRuleDtl1.setCreator("自动");
boolean insertDtl1Succ = sysCodeRuleDtlService.insert(sysCodeRuleDtl1);
assertThat("", insertDtl1Succ);
SysCodeRuleDtl sysCodeRuleDtl2 = new SysCodeRuleDtl();
sysCodeRuleDtl2.setSysCodeId(sysCodeRule.getId() + "");
sysCodeRuleDtl2.setOrderNo(2);
sysCodeRuleDtl2.setFieldValue("fieldName1");
sysCodeRuleDtl2.setCutBeginPosition(1);
sysCodeRuleDtl2.setCutEndPosition(3);
sysCodeRuleDtl2.setCreateTime(new Date());
sysCodeRuleDtl2.setCreator("自动");
boolean insertDtl1Succ2 = sysCodeRuleDtlService.insert(sysCodeRuleDtl2);
assertThat("", insertDtl1Succ2);
//------prepare test data end------------------------
//startLatch used to make sure all task threads start after
//prepared test data done
CountDownLatch startLatch = new CountDownLatch(1);
//parameters needed by the target method
Map<String, String> fieldValueMap = new HashMap<>(2);
fieldValueMap.put("locno", "cangku1");
fieldValueMap.put("fieldName1", "ABCDEFGH");
//doneLatch used to make sure all task threads done before the
//the transaction which started in main thread roll back
CountDownLatch doneLatch = new CountDownLatch(100);
for(int i = 0; i < 100; i++) {
new Thread(() -> {
try {
startLatch.await();
//this is the target method which i want to test
String result = sysCodeRuleService.createSheetIdWithoutUniformedSerial(codeRuleNo, JsonUtils.writeValueAsString(fieldValueMap));
if(CommonUtil.isNotNull(result)) {
logger.debug(">>>>>>>>>>>>>" + result);
}
} catch(InterruptedException e) {
e.printStackTrace();
} finally {
doneLatch.countDown();
}
}).start();
}
//guarantee the test data truly saved before all task treads
//start
EntityWrapper<SysCodeRule> ew = new EntityWrapper<>();
ew.eq("code_rule_no", codeRuleNo);
SysCodeRule codeRule = sysCodeRuleService.selectOne(ew);
if(codeRule != null) {
startLatch.countDown();
}
//main thread keep waiting until all task threads done their
//work
doneLatch.await();
}
BaseServiceTest
次のようになります。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class)
@Transactional
@Rollback
public class BaseServiceTest {
protected Logger logger = LoggerFactory.getLogger(BaseServiceTest.class);
}
そして、ターゲット・メソッドのシグネチャは次のようになります。
public synchronized String createSheetIdWithoutUniformedSerial(String codeRuleNo, String fieldValuesJson)
ターゲットメソッドでは、それが「準備試験データ」コードで保存されたデータは、ブロックいくつかのビジネスロジックコードは、結果を返却する照会します。ちなみに、「ビジネス・サービス・レイヤー」に書いたターゲット・メソッドは、春AOPによって管理されるトランザクション、およびこのようなトランザクション設定ファイルのルックスを持っています:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
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/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="doReweight" propagation="REQUIRES_NEW"/>
<tx:method name="doClear*" propagation="REQUIRES_NEW"/>
<tx:method name="doSend*" propagation="REQUIRES_NEW"/>
<tx:method name="doBatchSave*" propagation="REQUIRES_NEW"/>
<tx:method name="get*" propagation="REQUIRED" read-only="true"/>
<tx:method name="count*" propagation="REQUIRED" read-only="true"/>
<tx:method name="find*" propagation="REQUIRED" read-only="true"/>
<tx:method name="list*" propagation="REQUIRED" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config expose-proxy="true" proxy-target-class="true">
<aop:pointcut id="txPointcut"
expression="execution(* com.xxx..service..*+.*(..))"/>
<aop:advisor id="txAdvisor" advice-ref="txAdvice"
pointcut-ref="txPointcut"/>
</aop:config>
</beans>
私の予想結果はsyncronizedターゲットメソッドがうまく機能しています
だが!各サブタスクスレッドでは、対象の方法は、メインスレッドで作製し準備した試験データを照会することはできません!
だから、私は混乱していた、といくつかのヘルプやヒントが必要ですか?間違っていたものを、それを把握することはできません、私は本当に、皆さんから事前に感謝し、いくつかの助けに感謝します!
PS:春ブートverisonがある:1.5.10.RELEASE、Juiteバージョンは次のとおりです。4.12
あなた経由でデータベースとの最初の相互作用SysCodeRuleService
データベースにコミットされていない、テスト管理のトランザクション内の挿入試験データ。
呼び出しcreateSheetIdWithoutUniformedSerial()
あなたのSysCodeRuleService
新しいスレッドで、次に実行します。しかし、春には、新たに生成されたスレッドにトランザクションを伝播しません。このように、呼び出しのcreateSheetIdWithoutUniformedSerial()
中断テスト管理のトランザクションでコミットされていない試験データを見ることができない別のスレッドで実行されます。
できるようにするためにcreateSheetIdWithoutUniformedSerial()
、新しいスレッドで、データベースのようなテストデータを参照するには、任意の新しいスレッドを生成する前に、データベースにテストデータをコミットする必要があります。
これを達成するためのいくつかのオプションがあります。
あなたは非常に低レベルの技術を探しているなら、あなたは使用することができSpringのをTransactionTemplate
プログラム的にデータベースにコミットします。これは、偶数(経由、つまり代わりに、テスト管理のトランザクションで動作するはずです@Transactional
テストクラスや試験方法で)。
あなたが現在までのデータベースのセットアップの特定を行いたい場合@Test
の方法、別のオプションは使用することがあるTestTransaction
APIを。参照プログラムによるトランザクション管理を詳細については、春Frameworkリファレンス・マニュアルで。
あなたは現在のクラスのすべてのテストメソッドに同じデータベースのセットアップを実行したい場合は、導入することができ@BeforeTransaction
、データベースとにテストデータを挿入する方法@AfterTransaction
、データベースからテスト・データを削除する方法を。参照トランザクションのコードの外を実行します。
あなたがに喜んまたは(潜在的に外部ファイル内)文、INSERT SQLにテストデータの設定を移動することに興味がある場合は、使用することができSpringの@Sql支援を。
注意点として、あなたは安全に取り外すことができ@Rollback
ますが、効果的にデフォルトのセマンティクスを持つデフォルトのセマンティクスをオーバーライドしているので、宣言を。