Java (ObjectOptimisticLockingFailureException)单个事务中的StaleStateException
为了避免不必要的干扰,下面的代码被刻意简化和删节 我已使用mysql数据库和表:Java (ObjectOptimisticLockingFailureException)单个事务中的StaleStateException,java,mysql,hibernate,spring-transactions,optimistic-locking,Java,Mysql,Hibernate,Spring Transactions,Optimistic Locking,为了避免不必要的干扰,下面的代码被刻意简化和删节 我已使用mysql数据库和表: CREATE TABLE `payment` ( `id` int(11) NOT NULL AUTO_INCREMENT, `status` varchar(45) DEFAULT NULL, `last_update_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `id_U
CREATE TABLE `payment` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`status` varchar(45) DEFAULT NULL,
`last_update_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
我有一个从控制器调用的Spring事务方法
@GetMapping("/reproduce_error")
@Transactional
public ResponseEntity reproduceErrorOnUpdate(Long id) {
try {
Payment payment = paymentDao.getPayment(id); //1st query
payment.setStatus(payment.getStatus().equals("A") ? "B" : "A");
paymentDao.findAllByStatus("NOT EXISTING STATUS"); // 2nd query
payment.setStatus("C");
} catch (Exception e) {
return new ResponseEntity<>(e, HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity(HttpStatus.OK);
}
但同时(这也是最奇怪的事情):
如果我们省略了第二个查询(该查询返回null!),那么该方法将正常工作
这两种方法都在单个事务中执行!
(以下是我对它们的称呼,因此您可以看到,在某些地方没有其他交易)
没有不同的线程或HTTP调用使用同一个DB行(根据我在本地机器上复制的情况)。唯一的区别是,在第一种情况下(错误),我们在数据库中进行第二次搜索并出现错误(即使第二次搜索没有返回任何结果),而在第二种情况下(成功),我们没有这样做
我知道(在错误情况下)Hibernate会在执行对DB的第二次调用之前刷新更改,以支持一致性。但是为什么我们会有StaleStateException,因为我们处理它的每件事一个事务,并且在其中所做的每一个更改都应该是自己可见的
有人能帮我解决这种奇怪的休眠行为,并解释为什么会发生这种情况。我已经准备了一个可复制的最小应用程序,并将其放在bitbucket上: 我还在Hibernate项目的Jira中提出了一个问题: Hibernate团队帮了我。事实证明,这个问题是由Hibernate和MySql错误造成的,这两个错误都与刷新过程中的精度损失有关 解决方法之一是将DB列格式从TIMESTAMP更改为(例如)TIMESTAMP(6)或DATETIME(6)
org.springframework.orm.ObjectOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1