型号结构:
@MappedSuperclass public class BaseModel<K extends Comparable> implements Serializable, Comparable<Object> { private static final long serialVersionUID = 1L; @Id private K id; @Version private Integer version; // getter/setter } @Entity public class MyEntity extends BaseModel<String> { // some fields and it's getter/setter }
在我的数据库中记录my_entity:
my_entity
id:1版本:1 …
下面是我的更新方法:
void update(String id, Integer currentVersion, ....) { MyEntity myEntity = myRepository.findOne(id); myEntity.setVersion(currentVersion); // other assignments myRepository.save(myEntity); }
下面是调用此方法时触发的查询。
update my_entity set version=?, x=?, y=?, ... where id=? and version=?
当currentVersion在上述方法中传递的不是时,我期望OptimisticLockException 1。
currentVersion
1
谁能帮我为什么我没有得到OptimisticLockException?我正在为我的webmvc项目使用spring-boot。
JPA规范的11.1.54节指出:
通常,应用程序不应更新使用Version批注指定的字段或属性。
根据经验,我可以建议您尝试手动更新版本字段时,某些JPA提供程序(OpenJPA是其中之一)实际上会引发异常。
虽然不是严格回答您的问题,但是您可以按以下方式进行重构,以确保JPA提供程序之间的可移植性以及对JPA规范的严格遵守:
public void update(String id, Integer currentVersion) throws MyWrappedException { MyEntity myEntity = myRepository.findOne(id); if(currentVersion != myEntity.getVersion()){ throw new MyWrappedException(); } myRepository.save(myEntity); //still an issue here however: see below }
假设您的update(...)方法正在事务中运行,但是如JPA规范第3.4.5节所述,您仍然遇到上述问题:
update(...)
3.4.5 OptimisticLockException与有效的锁定模式和刷新模式设置一致时,提供程序实现可以将对数据库的写操作推迟到事务结束。在这种情况下,直到提交时间才可能进行乐观锁检查,并且可能在提交的“完成之前”阶段引发OptimisticLockException。 如果OptimisticLockException必须由应用程序捕获或处理,则应用程序应使用flush方法来强制执行数据库写操作。 这将允许应用程序捕获和处理乐观锁异常。
基本上,两个用户可以同时提交同一实体的修改。这两个线程都可以通过初始检查,但是当更新被刷新到数据库时可能会失败,这可能是在事务提交时执行的,即在您的方法完成之后。
为了可以捕获和处理OptimisticLock异常,代码应如下所示:
public void update(String id, Integer currentVersion) throws MyWrappedException { MyEntity myEntity = myRepository.findOne(id); if(currentVersion != myEntity.getVersion()){ throw new MyWrappedException(); } myRepository.save(myEntity); try{ myRepository.flush() } catch(OptimisticLockingFailureException ex){ throw new MyWrappedException(); } }