Я пишу приложение, которое периодически извлекает новые строки (row.status == 'NEW') из таблицы базы данных, выполняет некоторую обработку каждой строки как сущность JPA, затем сохраняет строку обратно в базу данных со статусом =='ОБРАБОТАНО'.
Таблица БД:
ID | Status
1 | PROCESSED
2 | NEW
3 | NEW
Java-код: (с использованием среды загрузки Spring)
@Component
public class Processor {
// an JPA repository for selecting Items
@Autowired
ItemRepository itemRepository;
// a thread executor for submitting
ExecutorService executor = Executors.newSingleThreadExecutor();
@Scheduled(fixed-rate=1000)
void process() {
List<Item> newItems = itemRepository.findByStatus('NEW');
for(Item item : newItems) {
// process each item asyncronously
executor.submit(()-> {
// do some processing on this item and update status.
// THis is time consuming process, may take 4 or 5 seconds
item.setStatus("PROCESSED");
itemRepository.save(item);
});
}
}
}
Проблема в том, что когда один элемент item1
все еще обрабатывается в executor
и не обновляется со статусом PROCESSED
, в следующем раунде обработки он все еще будет выбран itemRepository.findByStatus('NEW')
.И он будет снова отправлен на обработку.
Как избежать такого случая?(кроме изменения fixed-rate
на fixed-delay
) Существует ли какой-то механизм блокировки, такой как syncronize (item) { .... }
, такой, что, когда строка базы данных еще обрабатывается, она не выбирается снова в следующем раунде метода process()
?