为了确保本地多项数据操作的一致性,需要使用本地事务,本地事务的使用有一些需要注意的点:
示例代码如下:
/**
* 执行退款请求*
* @param request 请求参数
* @return 服务处理结果
*/
private Result processRefundRequest(final Request request) {
if (logger.isInfoEnabled()) {
logger.info("start to process request.");
}
final RefundRequest refundRequest = (RefundRequest) request;
Result result = transactionTemplate.execute(new TransactionCallback<Result>() {
@Override
public Result doInTransaction(TransactionStatus status) {
// 1.幂等控制
checkBnsUnique(refundRequest);
RefundOrder refundOrder = Convert.composeRefundOrder(refundRequest);
PayOrder = (PayOrder) OrderRepository.active(ServiceTypeEnum.PAY,
refundOrder.getPayOrderId());
// 3.判断支付单是否可以执行本次退款
couldPayOrderExecuteRefund(payOrder);
// 4.处理退款,更新退款单和支付单状态
Result result = updatePayOrderByRefundOrder(payOrder, refundOrder);
// 5.存储退款单,更新支付单
OrderRepository.store(refundOrder);
OrderRepository.update(payOrder);
return result;
}
});
if (logger.isInfoEnabled()) {
logger.info("refund request process end,result:" + result.DigiestString());
}
// 6.发送结果消息
sendResultMsg(result);
}
1、事务内部处理应遵循1)锁记录2)判断记录状态3)执行操作并更新记录,另外锁记录时关联资源的锁顺序应该全局保持一致,防止死锁。
2、事务内部处理包含try{}catch(){}异常处理模块时,要注意设置status.setRollbackOnly(),或者重新将异常抛出交由事务模版自动设置。防止吞掉异常导致忘记回滚脏数据。
3、对于新增数据操作,无法通过锁记录来控制并发,需要使用特定字段数据库唯一约束来做幂等(例如请求id,幂等策略有尝试插入等)
4、与事务核心逻辑无关的操作放到事务外部,尽量保持事务规模小。比如打日志,io操作,发结果消息等,可以降低事务耗时,降低数据库连接持有时间,高并发场景能有效提高系统tps