我在Spring data-jpa中使用HSQLDB 2.4.1。 我看到如果字段'@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在由process2更新之后,由“ process1”更新。为什么使用“锁定更新”? 一切正常,使用“ @Version”字段(然后process2出现异常)。
答案 0 :(得分:0)
您需要设置HSQLDB数据库的并发控制模型。如果要进行悲观锁定,请使用SET DATABASE TRANSACTION CONTROL LOCKS
。这将启用读取锁定和写入锁定。
有关详细信息,请参见指南http://hsqldb.org/doc/2.0/guide/sessions-chapt.html#snc_tx_tx_cc