У меня есть контроллер:
@GetMapping("/old")
public Product getOld() {
Product omeOld = productService.getOneOld();
log.info(String.valueOf(omeOld.getId()));
return omeOld;
}
Служба:
@Override
@Transactional
public Product getOneOld() {
Product aNew = productsRepository.findTop1ByStatusOrderByCountAsc("NEW");
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return aNew;
}
И репозиторий:
@Repository
public interface ProductsRepository extends JpaRepository<Product, Long> {
Product findTop1ByStatusOrderByCountAsc(String status);
}
Я запускаю JMeter и отправляю 5 запросов в 5 потоков.В результате я получаю 5 ответов через 5 секунд.Каждый запрос обрабатывался секундами.Но в журнале я вижу следующее:
2018-09-14 14:04:35.524 INFO 9048 --- [nio-8080-exec-1] c.e.l.demo.controller.ProductController : 1
2018-09-14 14:04:35.525 INFO 9048 --- [nio-8080-exec-2] c.e.l.demo.controller.ProductController : 1
2018-09-14 14:04:35.532 INFO 9048 --- [nio-8080-exec-3] c.e.l.demo.controller.ProductController : 1
2018-09-14 14:04:35.534 INFO 9048 --- [nio-8080-exec-4] c.e.l.demo.controller.ProductController : 1
2018-09-14 14:04:35.534 INFO 9048 --- [nio-8080-exec-6] c.e.l.demo.controller.ProductController : 1
Каждый поток выбирает одну и ту же строку и обрабатывает ее.Мне нужно, чтобы первый поток выбирал первый ряд, второй поток выбирал второй ряд и т. Д. Я пытаюсь использовать @Lock(LockModeType.PESSIMISTIC_WRITE)
:
@Lock(LockModeType.PESSIMISTIC_WRITE)
Product findTop1ByStatusOrderByCountAsc(String status);
Теперь, когда я запускаю JMeter
, у меня следующее поведение:
первый поток работает 5 секунд, после этого второй поток работает 5 секунд и т. д. 25 секунд все 5 потоков.И в журнале:
2018-09-14 14:11:40.564 INFO 13724 --- [nio-8080-exec-5] c.e.l.demo.controller.ProductController : 1
2018-09-14 14:11:45.566 INFO 13724 --- [nio-8080-exec-4] c.e.l.demo.controller.ProductController : 1
2018-09-14 14:11:50.567 INFO 13724 --- [nio-8080-exec-2] c.e.l.demo.controller.ProductController : 1
2018-09-14 14:11:55.568 INFO 13724 --- [nio-8080-exec-1] c.e.l.demo.controller.ProductController : 1
2018-09-14 14:12:00.570 INFO 13724 --- [nio-8080-exec-3] c.e.l.demo.controller.ProductController : 1
Все потоки выбирают одну и ту же строку (если я изменю эту косулю в первом потоке - он не будет выбран во втором потоке, если условия не совпадают).
Я пытаюсь это:
@Query(value = "Select * from products where status = ?1 order by count asc LIMIT 1 for update", nativeQuery = true)
Product findTop1ByStatusOrderByCountAsc(String status);
результат тот же.
Но мне нужно - первый поток выбрать первую строку и заблокировать ее / Второй поток выбрать следующую незаблокированную строку и процесс.Я пытаюсь следующее:
@Query(value = "Select * from products where status = ?1 order by count asc LIMIT 1 for update of products skip locked", nativeQuery = true)
Product findTop1ByStatusOrderByCountAsc(String status);
И все работает отлично!:
2018-09-14 14:25:00.355 INFO 7904 --- [io-8080-exec-10] c.e.l.demo.controller.ProductController : 4
2018-09-14 14:25:00.355 INFO 7904 --- [nio-8080-exec-4] c.e.l.demo.controller.ProductController : 3
2018-09-14 14:25:00.355 INFO 7904 --- [nio-8080-exec-9] c.e.l.demo.controller.ProductController : 1
2018-09-14 14:25:00.358 INFO 7904 --- [nio-8080-exec-5] c.e.l.demo.controller.ProductController : 5
2018-09-14 14:25:00.359 INFO 7904 --- [nio-8080-exec-2] c.e.l.demo.controller.ProductController : 6
Каждый выбор в каждом потоке выбирает одну строку из неблокированных строк!
Но как я могу повторить это с Oracle?В оракуле я не могу написать LIMIT 1
, и если я использую ROWNUM = 1
, каждый поток всегда выбирает одну и ту же строку.