Я создал простое приложение с весенней загрузкой, которое продемонстрирует, как происходят банковские транзакции. Я создал одну сущность «Счет» и создал одну конечную точку «дебет».
Здесь я вызываю api-код «debit» два раза одновременно, но списывается только одна сумма времени. Я хочу знать, как я могу заблокировать сущность счета, чтобы другой поток считывал обновленный баланс и также дебетовал во второй раз.
Я попытался заблокировать объект «учетная запись» с типом режима блокировки как PESSIMISTIC_WRITE, но он не работает.
Account.java
package hello;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.*;
@Table(name = "account")
@Entity // This tells Hibernate to make a table out of this class
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Account {
//@Version
@Column(name="version")
private Integer version;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer userId;
@Column(name = "name")
private String name;
@Column(name="balance")
private int balance;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Account{" +
"userId=" + userId +
", name='" + name + '\'' +
", balance=" + balance +
'}';
}
}
Конечная точка покоя
@GetMapping(path = "/debit")
public ResponseEntity<String> debit() {
Integer withdrawAmount = 100;
Integer userId = 1;
log.debug("debit {} from account id {} ",withdrawAmount,userId);
accountService.debit(userId,withdrawAmount);
return ResponseEntity.badRequest().body("debited");
}
AccountService.java
package hello.service;
import hello.Account;
import hello.AccountRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import java.util.Optional;
@Service
public class AccountService {
final private Logger log = LoggerFactory.getLogger(AccountService.class);
@Autowired
private AccountRepository accountRepository;
@Autowired
private EntityManager entityManager;
@Transactional
public void debit(Integer id,int balance){
Optional<Account> accountOptional = accountRepository.findById(id);
Account account = accountOptional.get();
entityManager.refresh(account, LockModeType.PESSIMISTIC_WRITE);
final int oldBalance = account.getBalance();
log.debug("current balance {}",oldBalance);
account.setBalance(oldBalance-balance);
accountRepository.save(account);
log.debug("debited");
}
}
AccountRepository.java
package hello;
import org.springframework.data.repository.CrudRepository;
// This will be AUTO IMPLEMENTED by Spring into a Bean called userRepository
// CRUD refers Create, Read, Update, Delete
public interface AccountRepository extends CrudRepository<Account, Integer> {
Account findOneByUserId(Integer userId);
}
моя запись в базе данных -
нажмите здесь, чтобы увидеть изображение
Для проверки этого сценария я написал на bash script
debit.sh
curl -I 'http://localhost:8080/demo/debit' &
curl -I 'http://localhost:8080/demo/debit' &
запустите это с помощью bash debit.sh
Таким образом, он может вызывать одну и ту же конечную точку покоя дважды.
Вывод, который я получаю
2019-03-27 14:17:36.375 DEBUG 11191 --- [nio-8080-exec-3] hello.MainController : debit 100 from account id 1
2019-03-27 14:17:36.376 DEBUG 11191 --- [nio-8080-exec-4] hello.MainController : debit 100 from account id 1
2019-03-27 14:17:36.394 DEBUG 11191 --- [nio-8080-exec-4] hello.service.AccountService : current balance 100
2019-03-27 14:17:36.394 DEBUG 11191 --- [nio-8080-exec-3] hello.service.AccountService : current balance 100
2019-03-27 14:17:36.395 DEBUG 11191 --- [nio-8080-exec-4] hello.service.AccountService : debited
2019-03-27 14:17:36.396 DEBUG 11191 --- [nio-8080-exec-3] hello.service.AccountService : debited
В обеих транзакциях текущий баланс равен 100 и дебетуется одинаково.
Здесь я хочу обновить баланс до -100.