Java 使用Spring数据JPA时如何处理ObjectOptimisticLockingFailureException和StaleObjectStateException?

Java 使用Spring数据JPA时如何处理ObjectOptimisticLockingFailureException和StaleObjectStateException?,java,spring,hibernate,concurrency,spring-data-jpa,Java,Spring,Hibernate,Concurrency,Spring Data Jpa,我正在开发一个小型的RESTful服务,它使用spring boot starter数据jpa依赖项,并将User域对象定义为@Entity和UsersRepository扩展crudepository。该服务使客户端能够重置忘记的密码。作为第一部分,从客户端接收电子邮件的方法将检查具有此类电子邮件的用户是否存在且未被禁用,如果存在,则为该用户创建临时重置令牌,对其进行更新,并向客户端发送带有该令牌的特殊链接: @RestController @请求映射 @验证 公共类重置令牌控制器{ 私有最终

我正在开发一个小型的RESTful服务,它使用
spring boot starter数据jpa
依赖项,并将
User
域对象定义为
@Entity
UsersRepository
扩展
crudepository
。该服务使客户端能够重置忘记的密码。作为第一部分,从客户端接收电子邮件的方法将检查具有此类电子邮件的用户是否存在且未被禁用,如果存在,则为该用户创建临时重置令牌,对其进行更新,并向客户端发送带有该令牌的特殊链接:

@RestController
@请求映射
@验证
公共类重置令牌控制器{
私有最终用户Repository usersRepo;
私有最终JavaMailSender;
@自动连线
公共ResetTokenController(UsersRepository usersRepo、JavaMailSender){
this.usersRepo=usersRepo;
this.mailssender=mailssender;
}
@GetMapping(path=“/auth/reset token”,products=“application/json”)
@ResponseStatus(HttpStatus.OK)
公共地图sendmeresetoken(@RequestParam)
@NotBlank(message=“参数`email`不能为空”)
@电子邮件(message=“参数`Email`无效”)
字符串(电子邮件){
//步骤#1:获取具有给定电子邮件的用户
User User=usersRepo.findByEmail(电子邮件)
.filter(用户::已启用)
.OrelsThrow(()->新的ResponseStatusException(未找到HttpStatus,
“未找到或当前已禁用给定电子邮件的用户”);
//步骤2:为用户创建重置令牌
字符串标记=UUID.randomUUID().toString();
user.setResetToken(令牌);
user.setExpBefore(LocalDateTime.now().plusHours(24));
//步骤#3:使用新令牌保存用户并发送指令
usersRepo.save(用户);
mimessage message=constructHtmlMessage(令牌、电子邮件);
发送(消息);
return Collections.singletonMap(“消息”,“用于重置密码的标记化链接”+
“已发送到提供的电子邮件,并将在未来24小时内处于活动状态。”);
}
//构造mime消息的助手方法
私有MimeMessage constructHtmlMessage(字符串令牌、字符串电子邮件){
//在这里,我们基于刚刚创建的令牌构建一个链接
//并将其与详细说明一起包含在信息中
返回mimeMessage;
}
}
然而,上面的代码有一个潜在的缺陷。假设,某人(例如,我们服务的管理员)意外地从另一个线程介入,并删除在步骤1和步骤3之间的中间某处从数据库中更新的用户。为了避免这种场景中可能出现的不一致性,我首先尝试用
@Transactional(隔离=隔离.可重复读取)
包装整个方法,但很快发现,这样做没有任何效果,因为在这种情况下,不管该方法是否用
@Transactional
注释,嵌套
StaleObjectStateException
ObjectOptimisticLockingFailureException
都会抛出

现在的问题是:如何处理这种例外?就我个人而言,我不希望将其翻译给客户机,到目前为止,我所做的唯一决定是将该方法的内部构件放入while循环中,如下所示:

publicmap sendMeResetToken(…){
while(true){
试一试{
//#1:获取具有给定电子邮件的用户
//#2:为用户创建重置令牌
//#3:更新用户并发送令牌
//在成功更新时保留循环
return Collections.singletonMap(“消息”,“用于重置密码的标记化链接”+
“已发送到提供的电子邮件,并将在未来24小时内处于活动状态。”);
}捕获(ObjectOptimisticLockingFailureException忽略){
//继续循环,从一开始再做一次尝试
}
}
}

是否有任何解决方案(可能更优雅,不使用while循环)来处理这种情况,以及在更一般的意义上,如何处理此类异常(我的意思是,
ObjectOptimisticLockingFailureException
StaleObjectStateException
)通常是在生产中处理的?

这里有详细的解释和解决方案-@AjayKumar,谢谢。现在清楚多了。