Я использую HSQLDB 2.4.1 с Spring data-jpa.Я вижу, что другой поток может обновить ту же строку, если поле '@Version' отсутствует.Spring выполняет "@Scheduled" обновление 2 потоков с особым статусом, означающим, что он еще не обработан.
Метод чтения в репозитории:
@Lock(LockModeType.PESSIMISTIC_READ)
@Query("select t from Task t where t.state = 0")
Page<Task> findUnprocessed(Pageable p);
'process1' и 'process2'выполнить почти то же самое простое обновление, но «process1» имеет более длительную паузу перед сохранением.
@Scheduled(fixedDelay = 10)
@Transactional(Transactional.TxType.REQUIRED)
public void process1() throws Exception {
try {
Task task = getTasks();
System.out.println("process1: " + task + " by " + Thread.currentThread().getName());
task.data= task.data + " by 1";
task.state = 1;
Thread.sleep(random.nextInt(4_000));
repo.save(task);
System.out.println("process1 updated: " + task.id);
System.out.println("process1 read same = " + repo.findById(task.id));
} catch (EmptyResultDataAccessException e) {
//do nothing
}
}
Журнал обработки:
process1: Task(id=1) by thr-1
process2: Task(id=1) by thr-2
process2 updated: 1
process2 read same = Task(id=1, data= by 2) <<!!!
process2: Task(id=2, data=) by thr-2
process2 updated: 2
process2 read same = Task(id=2, data= by 2)
process1 updated: 1
process1 read same = Task(id=1, data= by 1) <<!!!
В результате задача № 1 обновляется «process1»после того, как это было уже обновлено process2.Почему, если используется «блокировка для обновления»?С полем '@Version' все работает нормально (процесс2 получил исключение).