我创建了一个实体用户,它具有整数属性交易配额。我需要根据其值(value)更新交易配额。
如果大于0,则需要递减,否则需要保留其值。
这是我的算法。
- 从数据库检索用户实体。
- 检查交易额度,如果交易额度大于0,则减1。
- 保留更改后的用户实体。
在上述情况下,当并发请求到来时,如果两个线程检索相同的用户实体并且 然后两个线程读取相同的事务配额值,如果大于 0,则都减 1 并更新用户实体。
例如。
ThreadA: val = e.getTxnQuota(); val = 5
ThreadB: val = e.getTxnQuota(); val = 5
ThreadA: e.setTxnQuota(val- 1); val = 4
ThreadB: e.setTxnQuota(val- 1); val =4
ThreadA: eDao.save(e);
ThreadB: eDao.save(e);
在上述情况下,保存的值是 4 而不是 3。
那么有什么方法可以创建一个原子事务来检查事务配额并更新用户实体吗?
最佳答案
这称为锁定,通常最好使用乐观锁定。 JPA 提供了一个标准机制来做到这一点。只需向您的实体添加一个版本字段,并用 @Version 对其进行注释即可:
@Version
private long version;
瞧瞧!
每次保存用户时,其当前版本都会与数据库中的版本进行比较,并递增:
update user set ..., version = version + 1 where id = ... and version = theVersionOfTheUserWhenItWasLoaded
(这一切都是透明发生的)。
如果版本不匹配,则不会更新任何内容,JPA 引擎会检测到它,抛出 OptimisticLockException,并将事务标记为回滚。
旁注:在上面的场景中,不需要调用 save()
:对附加实体所做的所有更改都会自动保存在数据库中。无需保存实体。
关于mysql - 同时更新依赖于实体属性的实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10757270/