From c2651d0ad4e66d1a6ba1bd7983972c22791da703 Mon Sep 17 00:00:00 2001 From: ronger Date: Wed, 8 Feb 2023 16:33:19 +0800 Subject: [PATCH] =?UTF-8?q?:art:=20=E4=BA=A4=E6=98=93=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../forest/enumerate/TransactionCode.java | 3 +- .../mapper/TransactionRecordMapper.java | 10 +++- .../impl/TransactionRecordServiceImpl.java | 56 +++++++++++++------ .../java/mapper/TransactionRecordMapper.xml | 10 ++-- 4 files changed, 55 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/rymcu/forest/enumerate/TransactionCode.java b/src/main/java/com/rymcu/forest/enumerate/TransactionCode.java index 48edd92..4ada308 100644 --- a/src/main/java/com/rymcu/forest/enumerate/TransactionCode.java +++ b/src/main/java/com/rymcu/forest/enumerate/TransactionCode.java @@ -6,7 +6,8 @@ package com.rymcu.forest.enumerate; public enum TransactionCode { INSUFFICIENT_BALANCE(901, "余额不足"), - UNKNOWN_ACCOUNT(902, "账号不存在"); + UNKNOWN_ACCOUNT(902, "账号不存在"), + FAIL(903, "交易失败"); private int code; diff --git a/src/main/java/com/rymcu/forest/mapper/TransactionRecordMapper.java b/src/main/java/com/rymcu/forest/mapper/TransactionRecordMapper.java index 80879cc..8d24d35 100644 --- a/src/main/java/com/rymcu/forest/mapper/TransactionRecordMapper.java +++ b/src/main/java/com/rymcu/forest/mapper/TransactionRecordMapper.java @@ -16,11 +16,10 @@ public interface TransactionRecordMapper extends Mapper { * 交易 * * @param formBankAccount - * @param toBankAccount * @param money * @return */ - Integer transfer(@Param("formBankAccount") String formBankAccount, @Param("toBankAccount") String toBankAccount, @Param("money") BigDecimal money); + Integer debit(@Param("formBankAccount") String formBankAccount, @Param("money") BigDecimal money); /** * 查询指定账户的交易记录 @@ -48,4 +47,11 @@ public interface TransactionRecordMapper extends Mapper { * @return */ Boolean existsWithNewbieRewards(@Param("bankAccount") String bankAccount); + + /** + * @param toBankAccount + * @param money + * @return + */ + Integer credit(@Param("toBankAccount") String toBankAccount, @Param("money") BigDecimal money); } diff --git a/src/main/java/com/rymcu/forest/service/impl/TransactionRecordServiceImpl.java b/src/main/java/com/rymcu/forest/service/impl/TransactionRecordServiceImpl.java index f087bae..281b56b 100644 --- a/src/main/java/com/rymcu/forest/service/impl/TransactionRecordServiceImpl.java +++ b/src/main/java/com/rymcu/forest/service/impl/TransactionRecordServiceImpl.java @@ -18,40 +18,62 @@ import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.math.BigDecimal; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.Objects; +import java.util.*; +import java.util.concurrent.locks.ReentrantLock; /** * @author ronger */ @Service public class TransactionRecordServiceImpl extends AbstractService implements TransactionRecordService { - @Resource private TransactionRecordMapper transactionRecordMapper; @Resource private BankAccountMapper bankAccountMapper; @Resource private RedisService redisService; + private final Map userTransferLocks = new HashMap<>(); @Override @Transactional(rollbackFor = Exception.class) public TransactionRecord transfer(TransactionRecord transactionRecord) { - // 判断发起者账户状态 - boolean formAccountStatus = checkFormAccountStatus(transactionRecord.getFormBankAccount(), transactionRecord.getMoney()); - if (formAccountStatus) { - Integer result = transactionRecordMapper.transfer(transactionRecord.getFormBankAccount(), transactionRecord.getToBankAccount(), transactionRecord.getMoney()); - if (result > 0) { - transactionRecord.setTransactionNo(nextTransactionNo()); - transactionRecord.setTransactionTime(new Date()); - transactionRecordMapper.insertSelective(transactionRecord); + ReentrantLock lock = getUserTransferLocks(transactionRecord.getFormBankAccount()); + lock.lock(); + try { + // 判断发起者账户状态 + boolean formAccountStatus = checkFormAccountStatus(transactionRecord.getFormBankAccount(), transactionRecord.getMoney()); + boolean toAccountStatus = checkFormAccountStatus(transactionRecord.getToBankAccount(), BigDecimal.valueOf(0)); + if (formAccountStatus && toAccountStatus) { + Integer result = transactionRecordMapper.debit(transactionRecord.getFormBankAccount(), transactionRecord.getMoney()); + if (result > 0) { + result = transactionRecordMapper.credit(transactionRecord.getToBankAccount(), transactionRecord.getMoney()); + if (result > 0) { + transactionRecord.setTransactionNo(nextTransactionNo()); + transactionRecord.setTransactionTime(new Date()); + transactionRecordMapper.insertSelective(transactionRecord); + return transactionRecord; + } + } + } else if (toAccountStatus) { + throw new TransactionException(TransactionCode.INSUFFICIENT_BALANCE); + } else { + throw new TransactionException(TransactionCode.UNKNOWN_ACCOUNT); } - } else { - throw new TransactionException(TransactionCode.INSUFFICIENT_BALANCE); + } finally { + lock.unlock(); + } + throw new TransactionException(TransactionCode.FAIL); + } + + private ReentrantLock getUserTransferLocks(String formBankAccount) { + synchronized (userTransferLocks) { + ReentrantLock lock = userTransferLocks.get(formBankAccount); + if (lock == null) { + lock = new ReentrantLock(); + userTransferLocks.put(formBankAccount, lock); + } + return lock; } - return transactionRecord; } @Override @@ -162,7 +184,7 @@ public class TransactionRecordServiceImpl extends AbstractService 0; + return bankAccount.getAccountBalance().compareTo(money) >= 0; } return false; } diff --git a/src/main/java/mapper/TransactionRecordMapper.xml b/src/main/java/mapper/TransactionRecordMapper.xml index 7a6b022..791b2d6 100644 --- a/src/main/java/mapper/TransactionRecordMapper.xml +++ b/src/main/java/mapper/TransactionRecordMapper.xml @@ -11,13 +11,15 @@ - + update forest_bank_account set account_balance = account_balance - #{money} - where bank_account = #{formBankAccount}; + where bank_account = #{formBankAccount} and account_balance >= #{money} + + update forest_bank_account set account_balance = account_balance + #{money} - where bank_account = #{toBankAccount}; + where bank_account = #{toBankAccount} - \ No newline at end of file +