在并行事务中冻结插入

时间:2019-01-05 20:07:46

标签: mysql hibernate jdbc concurrency spring-data-jpa

我有两个具有共享倒计时闩锁的交易。每个事务在单独的线程中执行。我需要这种机制来重现“脏读”情况。 第一个事务确实更新了“目标实体”并刷新了更改而没有提交,然后将线程设置为等待状态(countDownLatch)。

在第二个事务中,我获取“目标实体”并将脏字段复制到另一个实体并进行保存。保存操作后,我使countDown继续第一个事务并回滚它。

下面的事务方法的代码示例。 第一个:

@Transactional
public void updatePrice() {
    log.info("Start price updating. Thread '{}'", Thread.currentThread().getName());
    Collection<Product> products = productRepository.findAll();
    products.forEach(this::updatePrice);
    productRepository.saveAll(products);
    entityManager.flush();
    log.info("Flash changes and wait for order transaction");
    try {
        latch.await();
    } catch (InterruptedException e) {
        log.error("Something wrong");
        Thread.currentThread().interrupt();
    }
    log.error("Rollback changes");
    throw new RuntimeException("Unexpected exception");

}

第二个:我有受事务和包装器服务限制的主服务,以递减锁存器。

包装器:

public void doOrder(Long productId, Long amount) {
    log.info("Start do order. Thread '{}'", Thread.currentThread().getName());
    orderService.doOrder(productId, amount);
    log.info("Order transaction committed");
    latch.countDown();
    log.info("Finish order process");
}

主要服务:

@Transactional
public void doOrder(Long productId, Long amount) {
    Product product = productRepository.findById(productId).get();
    log.info("Get product");
    Order order = Order.builder().price(product.getPrice()).amount(amount).productId(new Long(productId)).build();
    orderRepository.save(order);
    log.info("Save order");
}

所以,在行

  

orderRepository.save(order);

线程已冻结。我在日志中仅看到插入语句。

但是,如果我删除“订单”和“产品”之间的关系,则插入内容不会冻结。 我猜在'product'和countDownLatch上有死锁。但是,仅在mysql jdbc中会发生此问题。如果我切换到postgres jdbc,则那里没有问题。

PS: 第一个事务执行以下查询:

select * from product;
update product set price = ...

第二个执行:

select * from product where id = ...;
insert into product_order(product_id, amount, price) values (...)   

0 个答案:

没有答案