用户账户支付订单Java微服务后端架构实战

1. 架构概述

用户账户支付订单系统是电商平台和金融平台的核心模块,需要支持用户使用账户余额支付订单,保证支付流程的原子性、一致性和资金安全。本篇文章将深入讲解如何基于Java微服务架构实现一个高性能、高可用、资金安全的用户账户支付订单系统。

1.1 系统架构图

1
2
3
4
5
6
7
8
9
10
11
12
13
用户端 → 用户网关 → 用户服务 → 数据库

身份认证

订单允许支付(未支付)

账户余额充足,账户扣款

订单状态变更(已支付)

记录账户出入明细

返回支付信息

1.2 核心组件

  • 用户网关(User Gateway):负责用户请求的接入、身份认证、请求路由、流程编排
  • 用户服务(User Service):负责用户账户管理、账户扣款、账户明细记录
  • 订单服务(Order Service):负责订单管理、订单状态检查、订单状态变更
  • 数据库(MySQL):持久化账户信息、订单信息、账户明细
  • 分布式锁(Redisson):保证账户操作的并发安全
  • 分布式事务(Seata):保证支付流程的原子性和一致性

2. 用户网关服务实现

2.1 网关服务核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/**
* 用户网关服务
* 负责用户请求的接入、身份认证、请求路由、流程编排
*/
@RestController
@RequestMapping("/api/user/gateway")
@Slf4j
public class UserGatewayController {

@Autowired
private AuthService authService;

@Autowired
private UserServiceClient userServiceClient;

@Autowired
private OrderServiceClient orderServiceClient;

/**
* 用户发起支付请求
* 流程:身份认证 → 订单允许支付(未支付) → 账户余额充足,账户扣款 →
* 订单状态变更(已支付) → 记录账户出入明细 → 返回支付信息
*/
@PostMapping("/payment/pay")
public Result<PaymentResult> payOrder(
@RequestHeader("Authorization") String token,
@RequestBody PaymentRequest request) {

try {
// 1. 身份认证
UserInfo userInfo = authService.authenticate(token);
if (userInfo == null) {
return Result.error("身份认证失败");
}

// 2. 订单允许支付(未支付)
OrderInfo orderInfo = orderServiceClient.getOrderInfo(request.getOrderId());
if (orderInfo == null) {
return Result.error("订单不存在");
}

if (!OrderStatus.UNPAID.getCode().equals(orderInfo.getStatus())) {
return Result.error("订单状态不允许支付,当前状态: " + orderInfo.getStatus());
}

// 3. 账户余额充足,账户扣款
AccountDeductRequest deductRequest = new AccountDeductRequest();
deductRequest.setUserId(userInfo.getUserId());
deductRequest.setAmount(orderInfo.getAmount());
deductRequest.setOrderId(request.getOrderId());
deductRequest.setOrderNo(orderInfo.getOrderNo());

AccountDeductResult deductResult = userServiceClient.deductAccount(deductRequest);
if (!deductResult.isSuccess()) {
return Result.error("账户扣款失败: " + deductResult.getMessage());
}

// 4. 订单状态变更(已支付)
OrderStatusUpdateRequest statusUpdateRequest = new OrderStatusUpdateRequest();
statusUpdateRequest.setOrderId(request.getOrderId());
statusUpdateRequest.setStatus(OrderStatus.PAID.getCode());
statusUpdateRequest.setPayTime(new Date());
statusUpdateRequest.setTransactionNo(deductResult.getTransactionNo());

OrderStatusUpdateResult statusUpdateResult =
orderServiceClient.updateOrderStatus(statusUpdateRequest);
if (!statusUpdateResult.isSuccess()) {
// 扣款成功但订单状态更新失败,需要回滚账户扣款
log.error("订单状态更新失败,回滚账户扣款: orderId={}", request.getOrderId());
userServiceClient.rollbackAccountDeduct(deductResult.getTransactionNo());
return Result.error("订单状态更新失败,已回滚账户扣款");
}

// 5. 记录账户出入明细(已在扣款时记录,这里可以记录支付成功明细)
AccountDetailRequest detailRequest = new AccountDetailRequest();
detailRequest.setUserId(userInfo.getUserId());
detailRequest.setOrderId(request.getOrderId());
detailRequest.setOrderNo(orderInfo.getOrderNo());
detailRequest.setAmount(orderInfo.getAmount());
detailRequest.setTransactionNo(deductResult.getTransactionNo());
detailRequest.setType(AccountDetailType.PAYMENT.getCode());

userServiceClient.recordAccountDetail(detailRequest);

// 6. 返回支付信息
PaymentResult result = new PaymentResult();
result.setOrderId(request.getOrderId());
result.setOrderNo(orderInfo.getOrderNo());
result.setAmount(orderInfo.getAmount());
result.setTransactionNo(deductResult.getTransactionNo());
result.setPayTime(new Date());
result.setSuccess(true);
result.setMessage("支付成功");

log.info("用户账户支付订单成功: userId={}, orderId={}, amount={}",
userInfo.getUserId(), request.getOrderId(), orderInfo.getAmount());

return Result.success(result);

} catch (Exception e) {
log.error("用户账户支付订单失败: orderId={}, error={}",
request.getOrderId(), e.getMessage(), e);
return Result.error("支付失败: " + e.getMessage());
}
}
}

2.2 身份认证服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/**
* 身份认证服务
*/
@Service
@Slf4j
public class AuthService {

@Autowired
private RedisTemplate<String, Object> redisTemplate;

@Autowired
private UserServiceClient userServiceClient;

/**
* 身份认证
* 验证Token有效性
*/
public UserInfo authenticate(String token) {
try {
// 1. 从Token中解析用户信息
String userId = parseToken(token);
if (StringUtils.isEmpty(userId)) {
return null;
}

// 2. 从缓存中获取用户信息
String userCacheKey = "user:info:" + userId;
UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get(userCacheKey);

if (userInfo != null) {
return userInfo;
}

// 3. 缓存未命中,调用用户服务查询
userInfo = userServiceClient.getUserInfo(userId);

// 4. 将用户信息写入缓存
if (userInfo != null) {
redisTemplate.opsForValue().set(userCacheKey, userInfo, 30, TimeUnit.MINUTES);
}

return userInfo;

} catch (Exception e) {
log.error("身份认证失败: token={}, error={}", token, e.getMessage(), e);
return null;
}
}

/**
* 解析Token
*/
private String parseToken(String token) {
// JWT Token解析逻辑
if (StringUtils.isEmpty(token) || !token.startsWith("Bearer ")) {
return null;
}

String jwtToken = token.substring(7);
// 解析JWT获取userId
return extractUserIdFromJWT(jwtToken);
}

private String extractUserIdFromJWT(String jwtToken) {
// JWT解析实现
// 实际实现需要使用JWT库
return "user123";
}
}

3. 用户服务实现

3.1 用户服务核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/**
* 用户服务
* 负责用户账户管理、账户扣款、账户明细记录
*/
@Service
@Slf4j
public class UserAccountService {

@Autowired
private UserAccountMapper userAccountMapper;

@Autowired
private AccountDetailMapper accountDetailMapper;

@Autowired
private RedissonClient redissonClient;

/**
* 账户余额充足,账户扣款
* 检查账户余额是否充足,如果充足则扣款
*/
@Transactional(rollbackFor = Exception.class)
public AccountDeductResult deductAccount(AccountDeductRequest request) {
String lockKey = "account:lock:" + request.getUserId();
RLock lock = redissonClient.getLock(lockKey);

try {
if (lock.tryLock(10, TimeUnit.SECONDS)) {
// 1. 查询用户账户
UserAccount account = userAccountMapper.selectByUserId(request.getUserId());
if (account == null) {
return AccountDeductResult.failed("用户账户不存在");
}

// 2. 检查账户状态
if (account.getStatus() != AccountStatus.NORMAL) {
return AccountDeductResult.failed("账户状态异常,无法扣款");
}

// 3. 检查账户余额是否充足
if (account.getBalance().compareTo(request.getAmount()) < 0) {
return AccountDeductResult.failed("账户余额不足,当前余额: " + account.getBalance());
}

// 4. 扣款
BigDecimal balanceBefore = account.getBalance();
account.setBalance(account.getBalance().subtract(request.getAmount()));
account.setAvailableAmount(account.getAvailableAmount().subtract(request.getAmount()));
account.setTotalExpense(account.getTotalExpense().add(request.getAmount()));
account.setUpdateTime(new Date());
userAccountMapper.updateById(account);

// 5. 记录账户出入明细
String transactionNo = generateTransactionNo();
recordAccountDetail(account, request.getAmount(),
AccountDetailType.PAYMENT, balanceBefore, account.getBalance(),
request.getOrderId(), request.getOrderNo(), transactionNo);

log.info("账户扣款成功: userId={}, amount={}, balanceBefore={}, balanceAfter={}, transactionNo={}",
request.getUserId(), request.getAmount(), balanceBefore,
account.getBalance(), transactionNo);

// 6. 构建返回结果
AccountDeductResult result = new AccountDeductResult();
result.setSuccess(true);
result.setTransactionNo(transactionNo);
result.setBalanceBefore(balanceBefore);
result.setBalanceAfter(account.getBalance());
result.setMessage("账户扣款成功");

return result;

} else {
return AccountDeductResult.failed("账户操作超时,请稍后再试");
}
} catch (Exception e) {
log.error("账户扣款失败: userId={}, amount={}, error={}",
request.getUserId(), request.getAmount(), e.getMessage(), e);
return AccountDeductResult.failed("账户扣款失败: " + e.getMessage());
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}

/**
* 回滚账户扣款
* 当订单状态更新失败时,回滚账户扣款
*/
@Transactional(rollbackFor = Exception.class)
public void rollbackAccountDeduct(String transactionNo) {
try {
// 1. 查询账户明细
AccountDetail detail = accountDetailMapper.selectByTransactionNo(transactionNo);
if (detail == null) {
log.warn("账户明细不存在,无法回滚: transactionNo={}", transactionNo);
return;
}

// 2. 检查是否已回滚
if (detail.getStatus() == AccountDetailStatus.ROLLBACK) {
log.warn("账户扣款已回滚: transactionNo={}", transactionNo);
return;
}

// 3. 查询用户账户
UserAccount account = userAccountMapper.selectByUserId(detail.getUserId());
if (account == null) {
log.error("用户账户不存在,无法回滚: userId={}", detail.getUserId());
return;
}

// 4. 回滚账户余额
account.setBalance(account.getBalance().add(detail.getAmount()));
account.setAvailableAmount(account.getAvailableAmount().add(detail.getAmount()));
account.setTotalExpense(account.getTotalExpense().subtract(detail.getAmount()));
account.setUpdateTime(new Date());
userAccountMapper.updateById(account);

// 5. 记录回滚明细
recordAccountDetail(account, detail.getAmount(),
AccountDetailType.ROLLBACK, account.getBalance().subtract(detail.getAmount()),
account.getBalance(), detail.getOrderId(), detail.getOrderNo(),
generateTransactionNo());

// 6. 更新原明细状态
detail.setStatus(AccountDetailStatus.ROLLBACK);
detail.setUpdateTime(new Date());
accountDetailMapper.updateById(detail);

log.info("账户扣款回滚成功: transactionNo={}, amount={}",
transactionNo, detail.getAmount());

} catch (Exception e) {
log.error("账户扣款回滚失败: transactionNo={}, error={}",
transactionNo, e.getMessage(), e);
throw e;
}
}

/**
* 记录账户出入明细
*/
public void recordAccountDetail(AccountDetailRequest request) {
try {
// 查询用户账户
UserAccount account = userAccountMapper.selectByUserId(request.getUserId());
if (account == null) {
log.error("用户账户不存在: userId={}", request.getUserId());
return;
}

// 查询账户余额
BigDecimal balanceAfter = account.getBalance();
BigDecimal balanceBefore = balanceAfter.add(request.getAmount());

// 记录账户明细
recordAccountDetail(account, request.getAmount(),
AccountDetailType.PAYMENT, balanceBefore, balanceAfter,
request.getOrderId(), request.getOrderNo(), request.getTransactionNo());

} catch (Exception e) {
log.error("记录账户明细失败: userId={}, error={}",
request.getUserId(), e.getMessage(), e);
}
}

/**
* 记录账户出入明细(内部方法)
*/
private void recordAccountDetail(UserAccount account, BigDecimal amount,
AccountDetailType type,
BigDecimal balanceBefore,
BigDecimal balanceAfter,
Long orderId,
String orderNo,
String transactionNo) {
AccountDetail detail = new AccountDetail();
detail.setAccountId(account.getId());
detail.setUserId(account.getUserId());
detail.setAccountNo(account.getAccountNo());
detail.setTransactionNo(transactionNo);
detail.setOrderId(orderId);
detail.setOrderNo(orderNo);
detail.setType(type.getCode());
detail.setTypeName(type.getName());
detail.setAmount(amount);
detail.setBalanceBefore(balanceBefore);
detail.setBalanceAfter(balanceAfter);
detail.setDirection(type.getDirection());
detail.setStatus(AccountDetailStatus.SUCCESS);
detail.setRemark(type.getRemark());
detail.setCreateTime(new Date());
detail.setUpdateTime(new Date());

accountDetailMapper.insert(detail);
}

/**
* 生成交易号
*/
private String generateTransactionNo() {
return "TXN" + System.currentTimeMillis() + RandomUtils.nextInt(10000, 99999);
}
}

4. 订单服务实现

4.1 订单服务核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/**
* 订单服务
* 负责订单管理、订单状态检查、订单状态变更
*/
@Service
@Slf4j
public class OrderService {

@Autowired
private OrderMapper orderMapper;

@Autowired
private RedissonClient redissonClient;

/**
* 获取订单信息
*/
public OrderInfo getOrderInfo(Long orderId) {
Order order = orderMapper.selectById(orderId);
if (order == null) {
return null;
}

return convertToOrderInfo(order);
}

/**
* 订单允许支付(未支付)
* 检查订单状态是否允许支付
*/
public boolean isOrderAllowPayment(Long orderId) {
Order order = orderMapper.selectById(orderId);
if (order == null) {
return false;
}

// 检查订单状态是否为未支付
return OrderStatus.UNPAID.getCode().equals(order.getStatus());
}

/**
* 订单状态变更(已支付)
* 更新订单状态为已支付
*/
@Transactional(rollbackFor = Exception.class)
public OrderStatusUpdateResult updateOrderStatus(OrderStatusUpdateRequest request) {
String lockKey = "order:lock:" + request.getOrderId();
RLock lock = redissonClient.getLock(lockKey);

try {
if (lock.tryLock(10, TimeUnit.SECONDS)) {
// 1. 查询订单
Order order = orderMapper.selectById(request.getOrderId());
if (order == null) {
return OrderStatusUpdateResult.failed("订单不存在");
}

// 2. 检查订单状态
if (!OrderStatus.UNPAID.getCode().equals(order.getStatus())) {
return OrderStatusUpdateResult.failed("订单状态不允许更新,当前状态: " + order.getStatus());
}

// 3. 更新订单状态
order.setStatus(request.getStatus());
order.setPayTime(request.getPayTime());
order.setTransactionNo(request.getTransactionNo());
order.setUpdateTime(new Date());
orderMapper.updateById(order);

log.info("订单状态更新成功: orderId={}, status={}, transactionNo={}",
request.getOrderId(), request.getStatus(), request.getTransactionNo());

// 4. 构建返回结果
OrderStatusUpdateResult result = new OrderStatusUpdateResult();
result.setSuccess(true);
result.setOrderId(request.getOrderId());
result.setOrderNo(order.getOrderNo());
result.setStatus(request.getStatus());
result.setMessage("订单状态更新成功");

return result;

} else {
return OrderStatusUpdateResult.failed("订单操作超时,请稍后再试");
}
} catch (Exception e) {
log.error("订单状态更新失败: orderId={}, error={}",
request.getOrderId(), e.getMessage(), e);
return OrderStatusUpdateResult.failed("订单状态更新失败: " + e.getMessage());
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}

/**
* 转换订单为订单信息
*/
private OrderInfo convertToOrderInfo(Order order) {
OrderInfo info = new OrderInfo();
info.setOrderId(order.getId());
info.setOrderNo(order.getOrderNo());
info.setUserId(order.getUserId());
info.setAmount(order.getAmount());
info.setStatus(order.getStatus());
info.setCreateTime(order.getCreateTime());
info.setUpdateTime(order.getUpdateTime());
return info;
}
}

5. 数据模型定义

5.1 订单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/**
* 订单
*/
@Data
@TableName("order")
public class Order {
/**
* 主键ID
*/
@TableId(type = IdType.AUTO)
private Long id;

/**
* 订单号
*/
private String orderNo;

/**
* 用户ID
*/
private Long userId;

/**
* 订单金额
*/
private BigDecimal amount;

/**
* 订单状态:UNPAID-未支付, PAID-已支付, CANCELLED-已取消等
*/
private String status;

/**
* 交易号
*/
private String transactionNo;

/**
* 支付时间
*/
private Date payTime;

/**
* 创建时间
*/
private Date createTime;

/**
* 更新时间
*/
private Date updateTime;
}

5.2 订单状态枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 订单状态枚举
*/
public enum OrderStatus {
UNPAID("UNPAID", "未支付"),
PAID("PAID", "已支付"),
CANCELLED("CANCELLED", "已取消"),
REFUNDED("REFUNDED", "已退款");

private final String code;
private final String name;

OrderStatus(String code, String name) {
this.code = code;
this.name = name;
}

public String getCode() {
return code;
}

public String getName() {
return name;
}
}

5.3 账户明细类型枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* 账户明细类型枚举
*/
public enum AccountDetailType {
PAYMENT("PAYMENT", "订单支付", "EXPENSE", "订单支付"),
ROLLBACK("ROLLBACK", "支付回滚", "INCOME", "支付回滚"),
RECHARGE("RECHARGE", "充值", "INCOME", "账户充值"),
REFUND("REFUND", "退款", "INCOME", "账户退款");

private final String code;
private final String name;
private final String direction;
private final String remark;

AccountDetailType(String code, String name, String direction, String remark) {
this.code = code;
this.name = name;
this.direction = direction;
this.remark = remark;
}

public String getCode() {
return code;
}

public String getName() {
return name;
}

public String getDirection() {
return direction;
}

public String getRemark() {
return remark;
}
}

5.4 账户明细状态枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 账户明细状态枚举
*/
public enum AccountDetailStatus {
SUCCESS("SUCCESS", "成功"),
FAILED("FAILED", "失败"),
ROLLBACK("ROLLBACK", "已回滚");

private final String code;
private final String name;

AccountDetailStatus(String code, String name) {
this.code = code;
this.name = name;
}

public String getCode() {
return code;
}

public String getName() {
return name;
}
}

6. 请求和响应模型

6.1 支付请求

1
2
3
4
5
6
7
8
9
10
/**
* 支付请求
*/
@Data
public class PaymentRequest {
/**
* 订单ID
*/
private Long orderId;
}

6.2 支付结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* 支付结果
*/
@Data
public class PaymentResult {
/**
* 订单ID
*/
private Long orderId;

/**
* 订单号
*/
private String orderNo;

/**
* 支付金额
*/
private BigDecimal amount;

/**
* 交易号
*/
private String transactionNo;

/**
* 支付时间
*/
private Date payTime;

/**
* 是否成功
*/
private Boolean success;

/**
* 消息
*/
private String message;
}

6.3 账户扣款请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 账户扣款请求
*/
@Data
public class AccountDeductRequest {
/**
* 用户ID
*/
private Long userId;

/**
* 扣款金额
*/
private BigDecimal amount;

/**
* 订单ID
*/
private Long orderId;

/**
* 订单号
*/
private String orderNo;
}

6.4 账户扣款结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
* 账户扣款结果
*/
@Data
public class AccountDeductResult {
/**
* 是否成功
*/
private Boolean success;

/**
* 交易号
*/
private String transactionNo;

/**
* 扣款前余额
*/
private BigDecimal balanceBefore;

/**
* 扣款后余额
*/
private BigDecimal balanceAfter;

/**
* 消息
*/
private String message;

public static AccountDeductResult success() {
AccountDeductResult result = new AccountDeductResult();
result.setSuccess(true);
return result;
}

public static AccountDeductResult failed(String message) {
AccountDeductResult result = new AccountDeductResult();
result.setSuccess(false);
result.setMessage(message);
return result;
}
}

6.5 订单状态更新请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 订单状态更新请求
*/
@Data
public class OrderStatusUpdateRequest {
/**
* 订单ID
*/
private Long orderId;

/**
* 订单状态
*/
private String status;

/**
* 支付时间
*/
private Date payTime;

/**
* 交易号
*/
private String transactionNo;
}

7. 数据库Mapper实现

7.1 OrderMapper

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 订单Mapper
*/
@Mapper
public interface OrderMapper extends BaseMapper<Order> {

/**
* 根据订单号查询订单
*/
@Select("SELECT * FROM `order` WHERE order_no = #{orderNo} AND deleted = 0")
Order selectByOrderNo(@Param("orderNo") String orderNo);
}

7.2 AccountDetailMapper

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 账户明细Mapper
*/
@Mapper
public interface AccountDetailMapper extends BaseMapper<AccountDetail> {

/**
* 根据交易号查询明细
*/
@Select("SELECT * FROM account_detail WHERE transaction_no = #{transactionNo}")
AccountDetail selectByTransactionNo(@Param("transactionNo") String transactionNo);
}

8. 分布式事务处理

8.1 使用Seata实现分布式事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**
* 分布式事务支付服务
* 使用Seata保证支付流程的原子性
*/
@Service
@Slf4j
public class DistributedPaymentService {

@Autowired
private UserAccountService userAccountService;

@Autowired
private OrderService orderService;

/**
* 分布式事务支付
* 使用Seata的@GlobalTransactional保证整个支付流程的原子性
*/
@GlobalTransactional(rollbackFor = Exception.class)
public PaymentResult distributedPay(PaymentRequest request) {
try {
// 1. 账户扣款
AccountDeductRequest deductRequest = new AccountDeductRequest();
deductRequest.setUserId(request.getUserId());
deductRequest.setAmount(request.getAmount());
deductRequest.setOrderId(request.getOrderId());
deductRequest.setOrderNo(request.getOrderNo());

AccountDeductResult deductResult = userAccountService.deductAccount(deductRequest);
if (!deductResult.isSuccess()) {
throw new BusinessException("账户扣款失败: " + deductResult.getMessage());
}

// 2. 订单状态更新
OrderStatusUpdateRequest statusUpdateRequest = new OrderStatusUpdateRequest();
statusUpdateRequest.setOrderId(request.getOrderId());
statusUpdateRequest.setStatus(OrderStatus.PAID.getCode());
statusUpdateRequest.setPayTime(new Date());
statusUpdateRequest.setTransactionNo(deductResult.getTransactionNo());

OrderStatusUpdateResult statusUpdateResult =
orderService.updateOrderStatus(statusUpdateRequest);
if (!statusUpdateResult.isSuccess()) {
throw new BusinessException("订单状态更新失败: " + statusUpdateResult.getMessage());
}

// 3. 构建返回结果
PaymentResult result = new PaymentResult();
result.setOrderId(request.getOrderId());
result.setOrderNo(request.getOrderNo());
result.setAmount(request.getAmount());
result.setTransactionNo(deductResult.getTransactionNo());
result.setPayTime(new Date());
result.setSuccess(true);
result.setMessage("支付成功");

return result;

} catch (Exception e) {
log.error("分布式事务支付失败: orderId={}, error={}",
request.getOrderId(), e.getMessage(), e);
throw e;
}
}
}

8.2 Seata配置

1
2
3
4
5
6
7
8
9
10
11
/**
* Seata配置
*/
@Configuration
public class SeataConfig {

@Bean
public DataSourceProxy dataSourceProxy(DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
}

9. 幂等性处理

9.1 支付幂等性处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
* 支付幂等性处理
*/
@Service
@Slf4j
public class PaymentIdempotentService {

@Autowired
private RedisTemplate<String, Object> redisTemplate;

@Autowired
private OrderMapper orderMapper;

/**
* 检查支付是否已处理
*/
public boolean isPaymentProcessed(Long orderId) {
// 1. 检查Redis幂等性标记
String idempotentKey = "payment:idempotent:" + orderId;
String transactionNo = (String) redisTemplate.opsForValue().get(idempotentKey);
if (transactionNo != null) {
return true;
}

// 2. 检查订单状态
Order order = orderMapper.selectById(orderId);
if (order != null && OrderStatus.PAID.getCode().equals(order.getStatus())) {
return true;
}

return false;
}

/**
* 设置支付幂等性标记
*/
public void setPaymentIdempotent(Long orderId, String transactionNo) {
String idempotentKey = "payment:idempotent:" + orderId;
redisTemplate.opsForValue().set(idempotentKey, transactionNo, 7, TimeUnit.DAYS);
}
}

10. 性能优化策略

10.1 账户余额缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
* 账户余额缓存服务
*/
@Service
@Slf4j
public class AccountBalanceCacheService {

@Autowired
private RedisTemplate<String, Object> redisTemplate;

@Autowired
private UserAccountMapper userAccountMapper;

/**
* 获取账户余额(带缓存)
*/
public BigDecimal getAccountBalance(Long userId) {
String cacheKey = "account:balance:" + userId;
BigDecimal balance = (BigDecimal) redisTemplate.opsForValue().get(cacheKey);

if (balance != null) {
return balance;
}

// 缓存未命中,查询数据库
UserAccount account = userAccountMapper.selectByUserId(userId);
if (account != null) {
balance = account.getBalance();
// 写入缓存,过期时间5分钟
redisTemplate.opsForValue().set(cacheKey, balance, 5, TimeUnit.MINUTES);
}

return balance != null ? balance : BigDecimal.ZERO;
}

/**
* 更新账户余额缓存
*/
public void updateAccountBalanceCache(Long userId, BigDecimal balance) {
String cacheKey = "account:balance:" + userId;
redisTemplate.opsForValue().set(cacheKey, balance, 5, TimeUnit.MINUTES);
}

/**
* 删除账户余额缓存
*/
public void deleteAccountBalanceCache(Long userId) {
String cacheKey = "account:balance:" + userId;
redisTemplate.delete(cacheKey);
}
}

11. 总结

本文详细介绍了用户账户支付订单的Java微服务架构实现,包括:

  1. 用户网关服务:负责用户请求接入、身份认证、请求路由、流程编排
  2. 用户服务:负责用户账户管理、账户扣款、账户明细记录
  3. 订单服务:负责订单管理、订单状态检查、订单状态变更
  4. 支付流程
    • 身份认证
    • 订单允许支付(未支付)检查
    • 账户余额充足,账户扣款
    • 订单状态变更(已支付)
    • 记录账户出入明细
    • 返回支付信息
  5. 分布式事务:使用Seata保证支付流程的原子性和一致性
  6. 幂等性处理:防止重复支付
  7. 异常处理:支持账户扣款回滚

该架构具有以下优势:

  • 资金安全:分布式锁 + 分布式事务,保证资金安全
  • 高性能:账户余额缓存,查询延迟<5ms
  • 高可用:数据库持久化,支持数据恢复
  • 可扩展:微服务架构,支持水平扩展
  • 一致性:分布式事务保证支付流程的原子性
  • 幂等性:支持重复请求的幂等性处理

通过本文的实战代码,可以快速搭建一个高性能、高可用、资金安全的用户账户支付订单系统。