2016-05-17 17 views
0

私のプロジェクトでSpring Boot 1.3.3をベースにmybatisをmybatis-spring-boot-starter 1.1.1と永続化レイヤーとして統合しました。統合テストが失敗し、DB操作が非同期タスクでブロックされることがわかりました。 テストコードは次のようになります。MyBatis操作がSpring起動非同期メソッドでブロックされる

@RunWith(SpringJUnit4ClassRunner.class) 
@SpringApplicationConfiguration(classes = SapiApplication.class) 
@Transactional 
public class OrderIntegrationTest { 
    @Test 
    public void shouldUpdateOrder() throws InterruptedException{ 
     Order order1 = getOrder1(); 
     orderService.createOrder(order1); 

     Order order1updated = getOrder1Updated(); 
     orderService.updateOrderAsync(order1updated); 

     Thread.sleep(1000l); 

     log.info("find the order!"); 
     Order order1Db = orderService.findOrderById(order1.getOrderId()); 
     log.info("found the order!"); 
     assertEquals("closed", order1Db.getStatus()); 
    } 
} 

予想実行順序がcreateOrder()である - > updateOrderAsync() - > findOrderById()が、実際に実行順序がcreateOrder()される - > updateOrderAsync()を開始し、ブロック - > findOrderById() - > updateOrderAsync()は継続して終了しました。 ログ:

16:23:04.261 [executor1-1] INFO c.s.api.web.service.OrderServiceImpl - updating order: 2884384 
16:23:05.255 [main] INFO c.s.a.w.service.OrderIntegrationTest - find the order! 
16:23:05.280 [main] INFO c.s.a.w.service.OrderIntegrationTest - found the order! 
16:23:05.299 [executor1-1] INFO c.s.api.web.service.OrderServiceImpl - updated order: 2884384 

他の関連コード:

@Service 
public class OrderServiceImpl implements OrderService { 
    @Autowired 
    private OrderDao orderDao; 

    @Async("executor1") 
    @Override 
    public void updateOrderAsync(Order order){ 
     log.info("updating order: {}", order.getOrderId()); 
     orderDao.updateOrder(order); 
     log.info("updated order: {}", order.getOrderId()); 
    } 
} 

DAO:

public interface OrderDao { 
    public int updateOrder(Order order); 
    public int createOrder(Order order); 
    public Order findOrderById(String orderId); 
} 

のGradleの依存関係:

dependencies { 
    compile 'org.springframework.boot:spring-boot-starter-jdbc' 
    compile 'org.springframework.boot:spring-boot-starter-security' 
    compile 'org.springframework.boot:spring-boot-starter-web' 
    compile 'org.springframework.boot:spring-boot-starter-actuator' 
    compile 'org.mybatis.spring.boot:mybatis-spring-boot-starter:1.1.1' 
    compile 'ch.qos.logback:logback-classic:1.1.2' 
    compile 'org.springframework.boot:spring-boot-configuration-processor' 
    runtime 'mysql:mysql-connector-java' 
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 
    testCompile 'org.springframework.boot:spring-boot-starter-test' 
    testCompile "org.springframework.security:spring-security-test" 
} 

Spring構成:

@SpringBootApplication 
@EnableAsync 
@EnableCaching 
@EnableScheduling 
@MapperScan("com.sapi.web.dao") 
public class SapiApplication { 

@Bean(name = "executor1") 
protected Executor taskExecutor() { 
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 
    executor.setCorePoolSize(5); 
    executor.setMaxPoolSize(100); 
    return executor; 
} 

@Bean 
@Primary 
@ConfigurationProperties(prefix = "datasource.primary") 
public DataSource numberMasterDataSource() { 
    return DataSourceBuilder.create().build(); 
} 

@Bean(name = "secondary") 
@ConfigurationProperties(prefix = "datasource.secondary") 
public DataSource provisioningDataSource() { 
    return DataSourceBuilder.create().build(); 
} 

@Bean(name = "jdbcTpl") 
public JdbcTemplate jdbcTemplate(@Qualifier("secondary") DataSource dsItems) { 
    return new JdbcTemplate(dsItems); 
} 

public static void main(String[] args) { 
    SpringApplication.run(SapiApplication.class, args); 
} 
} 

プロパティ:

mybatis.mapper-locations=classpath*:com/sapi/web/dao/*Mapper.xml 
mybatis.type-aliases-package=com.sapi.web.vo 

datasource.primary.driver-class-name=com.mysql.jdbc.Driver 
datasource.primary.url=jdbc:mysql://10.0.6.202:3306/sapi 
datasource.primary.username=xxx 
datasource.primary.password=xxx 
datasource.primary.maximum-pool-size=80 
datasource.primary.max-idle=10 
datasource.primary.max-active=150 
datasource.primary.max-wait=10000 
datasource.primary.min-idle=5 
datasource.primary.initial-size=5 
datasource.primary.validation-query=SELECT 1 
datasource.primary.test-on-borrow=false 
datasource.primary.test-while-idle=true 
datasource.primary.time-between-eviction-runs-millis=18800 
datasource.primary.jdbc-interceptors=ConnectionState;SlowQueryReport(threshold=100) 

datasource.secondary.url = jdbc:mysql://10.0.6.202:3306/xdb 
datasource.secondary.username = xxx 
datasource.secondary.password = xxx 
datasource.secondary.driver-class-name = com.mysql.jdbc.Driver 

logging.level.org.springframework.web=DEBUG 

答えて

0

あなたが全体のテスト方法shouldUpdateOrderは、1つのトランザクションで実行されたことに起因する問題を参照。これは、shouldUpdateOrderを実行するスレッドで実行された更新操作は、トランザクションの全期間(つまり、テストメソッドから終了するまで)レコードをロックし、そのレコードを別の同時トランザクション(async方法)。

問題を解決するには、トランザクションの境界を変更する必要があります。あなたのケースでは、実際の生活の使用状況をエミュレートするための正しい方法は

  1. にあるさらに別のトランザクションで期待通りにその更新が実行されたチェック別のトランザクションで
  2. 更新順序
  3. を1つのトランザクションで順序を作成し、トランザクションを完了
+0

多くの感謝!私は多くの時間を節約しました。あなたのアドバイスに従って、トランザクション境界を変更し、問題を解決しました。 – qianlei

関連する問題