package com.erp.example.seata; import com.erp.example.seata.entity.Account; import com.erp.example.seata.entity.TransactionLog; import com.erp.example.seata.mapper.AccountMapper; import com.erp.example.seata.mapper.TransactionLogMapper; 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 java.math.BigDecimal; import java.time.LocalDateTime; import java.util.UUID; /** * 财务服务 - AT模式实现 */ @Service public class FinanceService { private static final Logger log = LoggerFactory.getLogger(FinanceService.class); @Autowired private AccountMapper accountMapper; @Autowired private TransactionLogMapper transactionLogMapper; /** * 冻结资金 * AT模式自动记录前后镜像,异常时自动回滚 */ @Transactional public void freezeAmount(Long customerId, Long amount, String orderNo) { log.info("冻结资金: 客户ID={}, 金额={}, 订单={}", customerId, amount, orderNo); Account account = accountMapper.findByCustomerId(customerId); if (account == null) { throw new RuntimeException("账户不存在: " + customerId); } BigDecimal availableAmount = account.getBalance().subtract(account.getFrozenAmount()); BigDecimal freezeAmount = BigDecimal.valueOf(amount); if (availableAmount.compareTo(freezeAmount) < 0) { throw new RuntimeException("余额不足: 可用=" + availableAmount + ", 需要=" + freezeAmount); } // 冻结资金 = 增加冻结金额 account.setFrozenAmount(account.getFrozenAmount().add(freezeAmount)); accountMapper.update(account); // 记录交易流水 TransactionLog txLog = new TransactionLog(); txLog.setTxNo("TX" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8)); txLog.setOrderNo(orderNo); txLog.setCustomerId(customerId); txLog.setAmount(freezeAmount); txLog.setType("FREEZE"); txLog.setStatus("SUCCESS"); txLog.setCreateTime(LocalDateTime.now()); transactionLogMapper.insert(txLog); log.info("资金冻结成功: {}", account); } /** * 解冻资金(取消冻结) * 用于订单取消时回滚 */ @Transactional public void unfreezeAmount(Long customerId, Long amount, String orderNo) { log.info("解冻资金: 客户ID={}, 金额={}, 订单={}", customerId, amount, orderNo); Account account = accountMapper.findByCustomerId(customerId); if (account == null) { log.warn("账户不存在: {}", customerId); return; } BigDecimal unfreezeAmount = BigDecimal.valueOf(amount); BigDecimal actualUnfreeze = unfreezeAmount.min(account.getFrozenAmount()); // 解冻资金 = 减少冻结金额 account.setFrozenAmount(account.getFrozenAmount().subtract(actualUnfreeze)); accountMapper.update(account); // 记录交易流水 TransactionLog txLog = new TransactionLog(); txLog.setTxNo("TX" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8)); txLog.setOrderNo(orderNo); txLog.setCustomerId(customerId); txLog.setAmount(actualUnfreeze); txLog.setType("UNFREEZE"); txLog.setStatus("SUCCESS"); txLog.setCreateTime(LocalDateTime.now()); transactionLogMapper.insert(txLog); log.info("资金解冻成功: {}", account); } /** * 消费资金(正式扣减) * 订单支付成功后调用 */ @Transactional public void consumeAmount(Long customerId, Long amount, String orderNo) { log.info("消费资金: 客户ID={}, 金额={}, 订单={}", customerId, amount, orderNo); Account account = accountMapper.findByCustomerId(customerId); if (account == null) { throw new RuntimeException("账户不存在: " + customerId); } BigDecimal consumeAmount = BigDecimal.valueOf(amount); // 消费资金 = 减少余额和冻结金额 account.setBalance(account.getBalance().subtract(consumeAmount)); account.setFrozenAmount(account.getFrozenAmount().subtract(consumeAmount)); accountMapper.update(account); // 记录交易流水 TransactionLog txLog = new TransactionLog(); txLog.setTxNo("TX" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8)); txLog.setOrderNo(orderNo); txLog.setCustomerId(customerId); txLog.setAmount(consumeAmount); txLog.setType("CONSUME"); txLog.setStatus("SUCCESS"); txLog.setCreateTime(LocalDateTime.now()); transactionLogMapper.insert(txLog); log.info("资金消费成功: {}", account); } /** * 退款 * 订单取消或退款时调用 */ @Transactional public void refundAmount(Long customerId, Long amount, String orderNo) { log.info("退款: 客户ID={}, 金额={}, 订单={}", customerId, amount, orderNo); Account account = accountMapper.findByCustomerId(customerId); if (account == null) { throw new RuntimeException("账户不存在: " + customerId); } BigDecimal refundAmount = BigDecimal.valueOf(amount); // 退款 = 增加余额 account.setBalance(account.getBalance().add(refundAmount)); accountMapper.update(account); // 记录交易流水 TransactionLog txLog = new TransactionLog(); txLog.setTxNo("TX" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8)); txLog.setOrderNo(orderNo); txLog.setCustomerId(customerId); txLog.setAmount(refundAmount); txLog.setType("REFUND"); txLog.setStatus("SUCCESS"); txLog.setCreateTime(LocalDateTime.now()); transactionLogMapper.insert(txLog); log.info("退款成功: {}", account); } /** * 查询账户 */ public Account findByCustomerId(Long customerId) { return accountMapper.findByCustomerId(customerId); } }