分布式事务解决方案:保障淘宝客APP资金结算的数据强一致性
分布式事务解决方案保障淘宝客APP资金结算的数据强一致性又见面了我是高佣返利省赚客APP研发者微赚在淘客返利业务中资金结算的准确性是平台的生命线。当用户订单确认收货后系统需要同时完成“订单状态更新”、“佣金计算入账”和“用户余额增加”三个操作。在微服务架构下这三个操作分散在不同的数据库实例中传统的本地Transactional注解失效。一旦某个环节失败极易导致“订单已结算但钱没到账”或“钱扣了但订单未更新”的严重资损事故。为了保障资金数据的强一致性或在极高并发下的最终一致性省赚客APP研发团队深入实践了TCCTry-Confirm-Cancel模式与可靠消息最终一致性方案。TCC模式的三阶段提交实战对于核心资金链路我们放弃了性能较差的XA协议转而采用TCC模式。TCC将事务拆分为Try尝试、Confirm确认、Cancel取消三个阶段。Try阶段进行资源预留和检查Confirm阶段执行真实业务Cancel阶段回滚预留资源。这种模式避免了长事务锁表显著提升了并发性能。packagejuwatech.cn.provinceearn.finance.tcc.service;importjuwatech.cn.provinceearn.finance.entity.UserWallet;importjuwatech.cn.provinceearn.finance.repository.WalletRepository;importjuwatech.cn.provinceearn.common.exception.InsufficientBalanceException;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;importlombok.extern.slf4j.Slf4j;importjava.math.BigDecimal;/** * 用户钱包服务的TCC实现 * 负责在分布式事务中管理余额的冻结与扣减 */Slf4jServicepublicclassWalletTccService{privatefinalWalletRepositorywalletRepository;publicWalletTccService(WalletRepositorywalletRepository){this.walletRepositorywalletRepository;}/** * Try阶段检查余额并冻结资金 * 此时资金并未真正扣除只是标记为“冻结”状态防止被其他事务使用 */TransactionalpublicbooleantryDeduct(StringuserId,BigDecimalamount,StringbizId){UserWalletwalletwalletRepository.findByUserId(userId);if(walletnull||wallet.getAvailableBalance().compareTo(amount)0){thrownewInsufficientBalanceException(Insufficient balance for user: userId);}// 记录冻结流水幂等性检查if(walletRepository.existsFreezeRecord(bizId)){returntrue;// 已经冻结过直接返回成功}// 执行冻结可用余额减少冻结余额增加wallet.freezeAmount(amount);walletRepository.save(wallet);// 插入冻结记录表用于Confirm/Cancel时查找walletRepository.saveFreezeRecord(bizId,userId,amount);log.info(Try phase success: frozen {} for user {},amount,userId);returntrue;}/** * Confirm阶段真正扣减资金 * 此阶段必须保证成功若失败需人工介入或无限重试 */TransactionalpublicvoidconfirmDeduct(StringbizId){varrecordwalletRepository.findFreezeRecord(bizId);if(recordnull){thrownewIllegalStateException(Freeze record not found for bizId: bizId);}// 将冻结余额真正扣除清除冻结标记walletRepository.deductFrozenAmount(record.getUserId(),record.getAmount());walletRepository.markFreezeRecordAsConfirmed(bizId);log.info(Confirm phase success: deducted for bizId {},bizId);}/** * Cancel阶段回滚冻结资金 * 将冻结的余额解冻恢复到可用余额 */TransactionalpublicvoidcancelDeduct(StringbizId){varrecordwalletRepository.findFreezeRecord(bizId);if(recordnull){return;// 幂等处理}// 解冻冻结余额减少可用余额增加walletRepository.unfreezeAmount(record.getUserId(),record.getAmount());walletRepository.markFreezeRecordAsCancelled(bizId);log.info(Cancel phase success: unfrozen for bizId {},bizId);}}基于本地消息表的最终一致性方案对于非实时强一致性的场景如积分赠送、通知发送我们采用了“本地消息表定时任务”的方案。该方案的核心思想是将“业务数据写入”与“消息发送”放在同一个本地数据库事务中确保消息一定被持久化。随后由独立的后台线程轮询消息表将消息投递到MQ并在投递成功后更新消息状态。packagejuwatech.cn.provinceearn.finance.message.handler;importjuwatech.cn.provinceearn.finance.entity.DomainEventLog;importjuwatech.cn.provinceearn.finance.repository.EventLogRepository;importjuwatech.cn.provinceearn.common.constant.EventStatus;importorg.apache.rocketmq.spring.core.RocketMQTemplate;importorg.springframework.scheduling.annotation.Scheduled;importorg.springframework.stereotype.Component;importorg.springframework.transaction.annotation.Transactional;importlombok.RequiredArgsConstructor;importjava.time.LocalDateTime;importjava.util.List;/** * 可靠消息投递处理器 * 解决本地事务与MQ发送的原子性问题 */ComponentRequiredArgsConstructorpublicclassReliableMessageSender{privatefinalEventLogRepositoryeventLogRepository;privatefinalRocketMQTemplaterocketMQTemplate;/** * 业务服务调用此方法保存事件必须在业务事务内执行 */TransactionalpublicvoidsaveEvent(StringeventType,StringbusinessId,Stringpayload){DomainEventLogeventLognewDomainEventLog();eventLog.setEventType(eventType);eventLog.setBusinessId(businessId);eventLog.setPayload(payload);eventLog.setStatus(EventStatus.PENDING);eventLog.setCreateTime(LocalDateTime.now());eventLog.setRetryCount(0);// 与业务数据同库同事务保存eventLogRepository.save(eventLog);}/** * 定时任务扫描待发送的消息并投递 * 频率不宜过高避免对数据库造成压力通常设置为每秒或每5秒一次 */Scheduled(fixedRate2000)publicvoidscanAndSend(){// 只查询超过3秒未发送的消息避免干扰刚写入的事务ListDomainEventLogpendingEventseventLogRepository.findPendingEvents(LocalDateTime.now().minusSeconds(3));for(DomainEventLogevent:pendingEvents){try{// 发送消息到MQrocketMQTemplate.syncSend(TOPIC_FINANCE_SETTLEMENT,event.getPayload());// 发送成功更新状态event.setStatus(EventStatus.SENT);event.setUpdateTime(LocalDateTime.now());eventLogRepository.save(event);}catch(Exceptione){// 发送失败增加重试次数event.setRetryCount(event.getRetryCount()1);if(event.getRetryCount()10){event.setStatus(EventStatus.FAILED);log.error(Message failed after 10 retries: {},event.getBusinessId(),e);}else{event.setUpdateTime(LocalDateTime.now());}eventLogRepository.save(event);}}}}防重与补偿机制分布式环境下网络抖动可能导致Confirm或消息重复投递。因此所有下游服务必须具备幂等性。我们在数据库中建立了唯一的业务流水号索引利用数据库的唯一约束来防止重复入账。同时针对TCC模式中Confirm阶段可能出现的长期阻塞我们设计了自动对账补偿任务每日凌晨扫描异常状态的分布式事务自动触发修复或报警人工处理。packagejuwatech.cn.provinceearn.finance.compensation.job;importjuwatech.cn.provinceearn.finance.repository.SettlementOrderRepository;importorg.springframework.batch.core.Job;importorg.springframework.batch.core.Step;importorg.springframework.batch.core.configuration.annotation.JobBuilderFactory;importorg.springframework.batch.core.configuration.annotation.StepBuilderFactory;importorg.springframework.batch.item.database.JdbcPagingItemReader;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importjavax.sql.DataSource;importjava.util.HashMap;importjava.util.Map;/** * 每日对账补偿任务配置 * 扫描状态不一致的结算单进行修复 */ConfigurationpublicclassCompensationJobConfig{privatefinalJobBuilderFactoryjobBuilderFactory;privatefinalStepBuilderFactorystepBuilderFactory;privatefinalDataSourcedataSource;publicCompensationJobConfig(JobBuilderFactoryjobBuilderFactory,StepBuilderFactorystepBuilderFactory,DataSourcedataSource){this.jobBuilderFactoryjobBuilderFactory;this.stepBuilderFactorystepBuilderFactory;this.dataSourcedataSource;}BeanpublicJobreconciliationJob(){returnjobBuilderFactory.get(reconciliationJob).start(reconciliationStep()).build();}BeanpublicStepreconciliationStep(){returnstepBuilderFactory.get(reconciliationStep).MapString,Object,Voidchunk(100).reader(abnormalOrderReader()).processor(item-{// 执行补偿逻辑根据订单状态强制修正资金流// 例如订单已结算但钱包未入账则手动触发入账compensateSettlement(item);returnnull;}).writer(list-{})// 无需写入补偿逻辑在processor中完成.build();}privateJdbcPagingItemReaderMapString,ObjectabnormalOrderReader(){JdbcPagingItemReaderMapString,ObjectreadernewJdbcPagingItemReader();reader.setDataSource(dataSource);reader.setFetchSize(100);reader.setRowMapper((rs,rowNum)-{MapString,ObjectmapnewHashMap();map.put(orderId,rs.getString(order_id));map.put(status,rs.getString(status));returnmap;});// 查询SQL查找状态不匹配的异常数据reader.setSelectStatement(SELECT order_id, status FROM t_settlement_order WHERE status PARTIAL_SUCCESS);returnreader;}privatevoidcompensateSettlement(MapString,Objectitem){// 具体的补偿业务逻辑实现System.out.println(Compensating order: item.get(orderId));}}结语资金安全无小事。通过TCC模式处理核心链路的强一致性需求配合本地消息表实现高吞吐场景下的最终一致性再辅以严密的幂等设计与自动对账补偿省赚客APP构建了一套坚不可摧的资金结算体系。这套架构不仅经受住了双11流量洪峰的考验更确保了每一分返利都准确无误地到达用户手中。本文著作权归 省赚客app 研发团队转载请注明出处

相关新闻

智谱AI:从多模态预训练到商业化落地的技术演进

智谱AI:从多模态预训练到商业化落地的技术演进

1. 从实验室到商业化的技术演进路径 2018年,一支来自清华大学的科研团队在自然语言处理领域取得突破性进展,这个后来被称为"智谱AI"的项目最初只是实验室里的几行代码。团队基于Transformer架构,创新性地提出了多模态预训练框架&am…

2026/7/25 20:25:46 阅读更多 →
AI智能体开发实战:Nexent平台电商客服搭建指南

AI智能体开发实战:Nexent平台电商客服搭建指南

1. 项目概述:AI智能体开发的新范式最近半年,AI智能体开发正在经历从实验室走向产业化的关键转折。不同于传统的单任务AI模型,智能体具备环境感知、自主决策和持续学习的能力,这使其在客服自动化、流程优化等场景展现出惊人潜力。N…

2026/7/25 20:24:46 阅读更多 →
Unreal Eangie 5:蓝图编辑

Unreal Eangie 5:蓝图编辑

实现玩家移动功能首先打开内容侧滑菜单右键打开后新建名为charrater(可以自定档案名)的档案先点击运行,我们发现我们什么都没做人物就可以跑动,这是因为项目模板中人物角色有默认的移动模板,今天我要自己来实现移动功能首先要把默认的移动模板…

2026/7/25 20:24:46 阅读更多 →

最新新闻

如何用浏览器直接查看和测量3D模型?Online3DViewer为你提供一站式解决方案

如何用浏览器直接查看和测量3D模型?Online3DViewer为你提供一站式解决方案

如何用浏览器直接查看和测量3D模型?Online3DViewer为你提供一站式解决方案 【免费下载链接】Online3DViewer A solution to visualize and explore 3D models in your browser. 项目地址: https://gitcode.com/gh_mirrors/on/Online3DViewer 想象一下&#x…

2026/7/25 20:32:49 阅读更多 →
Onekey终极指南:掌握Steam游戏清单下载与解锁配置的5个核心技巧

Onekey终极指南:掌握Steam游戏清单下载与解锁配置的5个核心技巧

Onekey终极指南:掌握Steam游戏清单下载与解锁配置的5个核心技巧 【免费下载链接】Onekey Onekey Steam Depot Manifest Downloader 项目地址: https://gitcode.com/gh_mirrors/one/Onekey Onekey是一款专为Steam平台设计的开源游戏解锁工具,通过自…

2026/7/25 20:32:49 阅读更多 →
ComfyUI-BrushNet终极指南:轻松实现AI图像修复与创意重绘

ComfyUI-BrushNet终极指南:轻松实现AI图像修复与创意重绘

ComfyUI-BrushNet终极指南:轻松实现AI图像修复与创意重绘 【免费下载链接】ComfyUI-BrushNet ComfyUI BrushNet nodes 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-BrushNet 你是否曾经遇到过这样的场景:一张完美的照片中有一个小小的瑕…

2026/7/25 20:32:49 阅读更多 →
为什么imFile能颠覆你的下载工作流?探索这款革命性下载管理器的智能解决方案

为什么imFile能颠覆你的下载工作流?探索这款革命性下载管理器的智能解决方案

为什么imFile能颠覆你的下载工作流?探索这款革命性下载管理器的智能解决方案 【免费下载链接】imfile-desktop A full-featured download manager. 项目地址: https://gitcode.com/gh_mirrors/im/imfile-desktop 你是否曾为下载大文件时速度缓慢而烦恼&#…

2026/7/25 20:32:49 阅读更多 →
Unity中LineRenderer被UI遮挡?RenderTexture+RawImage终极解决方案

Unity中LineRenderer被UI遮挡?RenderTexture+RawImage终极解决方案

1. 项目概述:当你的炫酷轨迹被UI无情覆盖 在Unity里做项目,尤其是那些带点策略、塔防或者需要高亮显示路径的游戏,LineRenderer组件绝对是你的好帮手。画个攻击范围、标个移动路线、做个技能特效,几行代码就能拉出一条平滑的曲线&…

2026/7/25 20:32:49 阅读更多 →
Linux运维学习路线:从零基础到企业级实战的完整指南

Linux运维学习路线:从零基础到企业级实战的完整指南

如果你正在寻找一套系统、完整且能真正带你从零基础入门到掌握企业级Linux运维技能的学习资源,那么这篇文章就是为你准备的。我们这次要看的不是某个单一的软件或模型,而是一个结构化的“学习路线图”和配套的“资源包”。它解决了初学者面对海量、零散的Linux运维教程时,不…

2026/7/25 20:31:49 阅读更多 →

日新闻

突破文档下载限制:kill-doc让你看到的都能保存

突破文档下载限制:kill-doc让你看到的都能保存

突破文档下载限制:kill-doc让你看到的都能保存 【免费下载链接】kill-doc 看到经常有小伙伴们需要下载一些免费文档,但是相关网站浏览体验不好各种广告,各种登录验证,需要很多步骤才能下载文档,该脚本就是为了解决您的…

2026/7/25 0:00:35 阅读更多 →
C++ string类模拟实现:从深拷贝到内存管理的完整指南

C++ string类模拟实现:从深拷贝到内存管理的完整指南

1. 项目概述:为什么我们要“手撕”string类?在C的学习道路上,尤其是从C语言过渡到C的“初阶”阶段,string类绝对是一个绕不开的核心。标准库里的std::string用起来太方便了,、find、substr,几个操作符和函数…

2026/7/25 0:00:35 阅读更多 →
三角洲寻宝鼠工具:高效文件搜索与资源管理实战指南

三角洲寻宝鼠工具:高效文件搜索与资源管理实战指南

1. 先搞清楚“三角洲寻宝鼠”到底是什么工具从名称来看,“三角洲寻宝鼠”更像是一个资源查找或文件检索类工具,而不是游戏或娱乐软件。这类工具的核心价值在于帮助用户快速定位特定资源,比如文档、图片、压缩包或特定格式的文件。如果你经常需…

2026/7/25 0:00:35 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/25 5:08:22 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/25 5:13:53 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/24 18:52:18 阅读更多 →

月新闻