数据库悲观锁与Spring数据JPA(Hibernate引擎盖下)

时间:2018-01-05 15:13:13

标签: spring hibernate jpa locking spring-data-jpa

我需要一些关于悲观实体锁定的帮助。我在我的应用程序中使用PostgreSQL和Spring数据JPA(引擎盖下的hibernate 5)。所以,我想展示一个我面临的任务。

我有一些有钱的用户帐户:

@lombok.Data //Used to generate getters and setters
@Entity
class AccountEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private Long balance;
}

付款,允许将资金从一个帐户转移到另一个帐户

@lombok.Data
@Entity
class PaymentEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private Long amount;

    @OneToOne
    @JoinColumn(name="account_from_id")
    private AccountEntity accountFrom;

    @OneToOne
    @JoinColumn(name="account_to_id")
    private AccountEntity accountTo;
}

两者的存储库:

interface AccountRepository extends JpaRepository<AccountEntity, Integer> {}

interface PaymentRepository extends JpaRepository<PaymentEntity, Integer> {}

进行汇款的服务:

interface PaymentService {
    PaymentEntity create(PaymentEntity paymentEntity);
}

@Service
class PaymentServiceImpl implements PaymentService {

    @Autowired
    private AccountRepository accountRepository;

    @Autowired
    private PaymentRepository paymentRepository;


    @Transactional
    @Override
    public PaymentEntity create(PaymentEntity payment) {
        AccountEntity from = accountRepository.getOne(payment.getAccountFrom().getId()); //want to lock account here
        AccountEntity to = accountRepository.getOne(payment.getAccountTo().getId()); //want to lock account here
        Long newFromBalance = from.getBalance() - payment.getAmount();
        Long newToBalance = to.getBalance() + payment.getAmount();
        if (newFromBalance < 0)
            throw new RuntimeException("Not enough money for payment");
        from.setBalance(newFromBalance);
        to.setBalance(newToBalance);
        PaymentEntity result = paymentRepository.save(payment); //create payment
        accountRepository.save(from); //update account
        accountRepository.save(to); //update account
        return result; //want to unlock both accounts here
    }
}

所以,正如你从代码中看到的那样,我想锁定两个账户,这些账户涉及交易开始时的汇款(这将保证在交易提交之前它们都无法更改,每个新的付款将获得帐户的更新余额)。在交易结束时,我想解锁它们。

我已经阅读了documentation,正如我和我所理解的那样,为此我需要更新我的AccountRepository

interface AccountRepository extends JpaRepository<AccountEntity, Integer> {
    @Lock(LockModeType.PESSIMISTIC_WRITE)
    AccountEntity save(AccountEntity account);
}

上述代码必须在交易开始时锁定fromto帐户,并在结束时自动解锁。但我还有一些问题:

  1. 在这种情况下,将使用数据库锁(而不是java端的应用程序),因为我使用的是应用程序的多个实例,它们使用相同的数据库。不是吗?
  2. 注释@Lock(LockModeType.PESSIMISTIC_WRITE)只能应用于存储库方法(不适用于服务方法)。不是吗?
  3. @Lock将锁定事务中的所有实体,已执行select(在我的情况下为fromto个帐户)。不是吗?
  4. 当事务提交或回滚时,所有​​锁定的实体将自动解锁。不是吗?
  5. 每次付款,使用帐户,以悲观的写锁定锁定将等到帐户更新并锁定将被释放。不是吗?
  6. 如果您提供官方文档或某些网站的链接,我将非常感谢,我可以自己发现这个主题。

0 个答案:

没有答案