У меня есть две транзакции с общим делом обратного отсчета. Каждая транзакция выполняется в отдельном потоке. Мне нужен такой механизм, чтобы воспроизвести ситуацию «грязного чтения».
Первая транзакция выполняет обновление «целевой сущности» и сбрасывает изменения без фиксации, затем я устанавливаю поток в состояние ожидания (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");
}
Второй: у меня есть основной сервис, который ограничен транзакцией и сервисом-оберткой для отсчета защелки.
Wrapper:
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', вставка не замерзнет.
Я предполагаю, что есть «тупик» на «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 (...)