java – 处理spring数据中的并发事务
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了java – 处理spring数据中的并发事务,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含8857字,纯文字阅读大概需要13分钟。
内容图文
![java – 处理spring数据中的并发事务](/upload/InfoBanner/zyjiaocheng/828/4b689f9d480c454c82086e4e3e3e58d3.jpg)
我正在使用spring Data.
我有弹簧数据并发事务的问题如下:
实体和存储库如下:
@Entity
public class Wallet {
@Version
private int version;
@Id
@GeneratedValue
@OrderColumn
private Long Id;
@OneToOne()
@OrderColumn
private User user;
@OrderColumn
private Double virtualBalance;
@Column(name = "created_by")
@OrderColumn
private String createdBy;
@Column(name = "created_date")
@OrderColumn
private Date createdDate;
@Column(name = "updated_by")
@OrderColumn
private String updatedBy;
@Column(name = "updated_date")
@OrderColumn
private Date updatedDate;
... Setters and getters ...
}
存储库如下
public interface WalletJpaRepository extends JpaRepository<Wallet, Long>{
@Lock(LockModeType.OPTIMISTIC) // I have also tried PESSIMISTIC, READ, WRITE, PESSIMISTIC_READ, PESSIMISTIC_WRITE, etc.but they don't seem to work
Wallet findOne(Long id);
}
我正在同时调用两个方法,如下所示:
@Test
public void testConcurrentTransactions() {
System.out.println("Wallet 1 : ->" + getWallet1());
System.out.println("Wallet 2 : ->" + getWallet2());
}
这两种方法如下所述
@Transactional(isolation = Isolation.SERIALIZABLE)
private Wallet getWallet1() {
Wallet wallet1 = walletJpaRepository.findOne(new Long(1)); // suppose the value of wallet1.getVirtualBalance() is 1000
wallet1.setVirtualBalance(wallet1.getVirtualBalance().doubleValue() + 100); // After evaluating this line it becomes 1100
System.out.println(Thread.currentThread().getId());
return wallet1;
}
@Transactional(isolation = Isolation.SERIALIZABLE)
private Wallet getWallet2() {
Wallet wallet2 = walletJpaRepository.findOne(new Long(1)); // Here again the value of wallet2.getVirtualBalance() fetched is 1000 but I need 1100 to be the value read
System.out.println(Thread.currentThread().getId());
return wallet2;
}
问题是我没有在不同的方法调用中获得相同实体的更新值.
例如,如果在调用方法getWallet1()之后,id为1的实体的值最初为1000,则该值应更新为1100,但它不会反映在第二个方法中,即getWallet2(),并且我再次得到1000在上面代码的注释中解释的第二种方法中.
我尝试过传播,隔离,锁定,但仍然没有得到所需的结果.
有没有一个解决方案来处理这样的场景,我无法找到这种情况的解决方案,这是一个简化版本的scenerio,我在一个巨大的货币交易系统,其命中率大约是4到5每秒交易量.
以上只是我试图重现场景的一个例子,下面是相同的实际代码.
@Override
@Transactional
public InterWalletRequestFrontendWrapper approveOrDeclineRequest(User requestingUser, String operation,
String requestId) {
InterWalletRequest walletRequest = interWalletRequestJpaRepository.findOne(Long.parseLong(requestId));
if (walletRequest.getStatus().equalsIgnoreCase(Utility.statusInitiated)
|| walletRequest.getStatus().equalsIgnoreCase(Utility.statusPending)) {
if (operation.equalsIgnoreCase(Utility.operationDecline)) {
walletRequest.setStatus(Utility.statusDeclined);
interWalletRequestJpaRepository.save(walletRequest);
InterWalletRequestFrontendWrapper response = fetchRaisedRequests(requestingUser);
response.setStatus(0);
response.setStatusDesc(Utility.statusDeclined);
return response;
} else {
User admin = walletRequest.getRequestTo();
Wallet adminWallet = admin.getWallet();
if (adminWallet.getVirtualBalance() >= walletRequest.getAmount()) {
try {
User user = walletRequest.getRequestFrom();
UserWalletTransaction txn1 = new UserWalletTransaction();
UserWalletTransaction txn2 = new UserWalletTransaction();
/**
* New transaction initiated for admin
*/
txn1.setAmountTransacted(walletRequest.getAmount());
txn1.setDebitUser(admin);
txn1.setCreditUser(user);
txn1.setOperationPerformed(Utility.operationPerformedInterWallet);
txn1.setPreviousAmount(admin.getWallet().getVirtualBalance());
txn1.setStatus(Utility.statusNew);
txn1.setUser(admin);
txn1.setTransactionType(Utility.transactionTypeDebit);
txn1.setCreatedBy(admin.getUserName());
txn1.setUpdatedBy(admin.getUserName());
txn1.setCreatedDate(new Date());
txn1.setUpdatedDate(new Date());
txn1.setWallet(admin.getWallet());
/**
* New txn initiated for the user who walletRequested
* the txn.
*/
txn2.setAmountTransacted(walletRequest.getAmount());
txn2.setDebitUser(admin);
txn2.setCreditUser(user);
txn2.setOperationPerformed(Utility.operationPerformedInterWallet);
txn2.setPreviousAmount(user.getWallet().getVirtualBalance());
txn2.setStatus(Utility.statusNew);
txn2.setTransactionType(Utility.transactionTypeCredit);
txn2.setCreatedBy(admin.getUserName());
txn2.setUpdatedBy(admin.getUserName());
txn2.setCreatedDate(new Date());
txn2.setUpdatedDate(new Date());
txn2.setUser(user);
txn2.setWallet(user.getWallet());
txn2 = walletTransactionJpaRepository.save(txn2);
Wallet wallet1 = admin.getWallet();
wallet1.setVirtualBalance(admin.getWallet().getVirtualBalance() - walletRequest.getAmount());
wallet1 = walletJpaRepository.save(wallet1);
/**
* After debit set the reference of other user.
*/
txn1.setRelationalTransaction(txn2);
/**
* After debit from admin set balance amount
*
*/
txn1.setBalanceAmount(wallet1.getVirtualBalance());
/**
* Money deducted from admin wallet but not credited to
* the user wallet. so status is pending.
*/
txn1.setStatus(Utility.statusPending);
txn1 = walletTransactionJpaRepository.save(txn1);
Wallet wallet2 = user.getWallet();
wallet2.setVirtualBalance(user.getWallet().getVirtualBalance() + walletRequest.getAmount());
wallet2 = walletJpaRepository.save(wallet2);
/**
* After credit to User wallet add balance amount.
*/
txn2.setBalanceAmount(wallet2.getVirtualBalance());
txn1.setStatus(Utility.statusSuccess);
txn2.setStatus(Utility.statusSuccess);
txn2.setRelationalTransaction(txn1);
List<UserWalletTransaction> transactions = new ArrayList<>();
transactions.add(txn1);
transactions.add(txn2);
walletTransactionJpaRepository.save(transactions);
walletRequest.setStatus(Utility.statusApproved);
interWalletRequestJpaRepository.save(walletRequest);
InterWalletRequestFrontendWrapper response = fetchRaisedRequests(requestingUser);
response.setStatus(0);
response.setBalance(wallet1.getVirtualBalance());
response.setStatusDesc(Utility.statusApproved);
return response;
} catch (Exception e) {
System.out.println(".......... Exception Caught ..........");
walletRequest.setStatus(Utility.statusPending);
interWalletRequestJpaRepository.save(walletRequest);
InterWalletRequestFrontendWrapper response = fetchRaisedRequests(requestingUser);
response.setStatus(0);
response.setStatusDesc(Utility.statusDeclined);
return response;
}
} else {
/**
* if the admin wallet desn't have enough balance then the
* status is set to pending.
*/
walletRequest.setStatus(Utility.statusPending);
interWalletRequestJpaRepository.save(walletRequest);
InterWalletRequestFrontendWrapper response = fetchRaisedRequests(requestingUser);
response.setStatus(0);
response.setStatusDesc(Utility.statusDeclined);
return response;
}
}
} else {
InterWalletRequestFrontendWrapper response = fetchRaisedRequests(requestingUser);
response.setStatus(0);
response.setStatusDesc(Utility.statusDeclined);
return response;
}
}
另一种在同一实体上运行的方法如下所示
@Override
@Transactional
private UserWalletTransaction initiateVerifyTransaction(AccountsDetails transfer, User user) {
Double amountTransacted = 2.00;
Wallet wallet = user.getWallet();
UserWalletTransaction transaction = new UserWalletTransaction();
transaction.setAmountTransacted(amountTransacted);
transaction.setPreviousAmount(wallet.getVirtualBalance());
transaction.setOperationPerformed(Utility.operationPerformedDVBeneFundTransfer);
transaction.setTransactionType(Utility.transactionTypeDebit);
/**
* Debit from wallet.
*/
wallet.setVirtualBalance(wallet.getVirtualBalance() - amountTransacted);
wallet.setUpdatedDate(new Date());
wallet.setUpdatedBy(user.getUserName());
wallet = walletJpaRepository.save(wallet);
logger.info(wallet);
transaction.setBalanceAmount(wallet.getVirtualBalance());
transaction.setUser(user);
transaction.setWallet(wallet);
transaction.setStatus(Utility.statusNew);
transaction.setCreatedBy(user.getUserName());
transaction.setUpdatedBy(user.getUserName());
transaction.setCreatedDate(new Date());
transaction.setToAccount(transfer.getAccount());
transaction.setBankName(transfer.getBankName());
transaction.setBeniMobile(transfer.getRecipientMobileNo());
transaction.setTransactionMode(transfer.getChannel().equalsIgnoreCase("2")
? "IMPS" : "NEFT");
return walletTransactionJpaRepository.save(transaction);
}
像这样,在不同服务中有七种方法可以同时访问钱包,因为可以同时登录多个用户,并且概率是用户管理员也登录并执行货币交易,即我们遇到这个问题的真实场景.
提前致谢
最佳答案:
大家好,我将回答我自己的问题,这可能会对将来有所帮助,我找到了解决问题的方法.感谢Denium指出了问题所在.这真是一个伟大的概念.
我正在做的错误是对方法进行内部调用并在私有方法上编写@Transactional.
@Transactional是使用spring AOP实现的,内部方法调用永远不会实际到达代理,并且@Transactional的功能行为很奇怪.
因此,解决方案是将方法包装在对象中,并在对象的方法上定义@Transactional,并仅对对象进行外部调用.
其他解决方案可能是定义我们自己的削减点和建议
有关更多参考,请访问以下链接:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html
https://www.mkyong.com/spring/spring-aop-example-pointcut-advisor/
请随意添加任何建议和编辑,
谢谢
内容总结
以上是互联网集市为您收集整理的java – 处理spring数据中的并发事务全部内容,希望文章能够帮你解决java – 处理spring数据中的并发事务所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。