【业务】利用防重ID避免重复落库,确保幂等性

场景

服务端发起订单落库请求后,已成功写入数据库。此时发生网络波动,数据库传回的信息未传送到服务端。服务端超时后再次发起落库请求,产生第二次落库。这种情况不符合幂等性。

幂等性

幂等性(Idempotence)是计算机科学中的一个概念,用于描述一个操作在执行一次和执行多次的结果是相同的。换句话说,如果它的多次执行不会对系统的状态产生额外的影响,即无论执行多少次,系统的最终状态都是一致的,这种情况下,该操作是幂等的。

解决方案

利用防重ID+编程式事务防止二次落库

在数据库中加入带有唯一性约束的bizID,在库表中已经存在该bizID时会返回重复键异常(DuplicateKeyException),捕捉到此异常就利用编程式事务进行事务回滚(恢复到二次落库前状态),从而确保幂等

防重ID的生成

需要确保bizID在业务层生成,并且在请求发起前就已经生成并传递到数据库

大厂一般会基于雪花算法开发自己的全局分布式ID生成器,生产全局唯一的业务ID。

幂等性设计

在业务逻辑中,不仅要在数据库层面实现幂等性,还应确保整个服务层的逻辑也是幂等的。例如,在处理订单时,可以考虑在业务逻辑中检查bizID是否已经处理过,而不仅仅是在数据库层面进行检查。

编程式事务

编程式事务Programmatic Transaction)是指在代码中显式地管理事务的生命周期,包括开始、提交和回滚。与声明式事务不同,编程式事务为开发者提供了更大的灵活性和精细的控制权。

Spring 中的编程式事务

在 Spring 框架中,编程式事务通常通过 TransactionTemplatePlatformTransactionManager 实现。这些类提供了用于显式管理事务的 API。

以下实例中,用status.setRollbackOnly(); 就可以回滚编程式事务块(execute中的业务代码)

实例【通过订单表中的bizID防重复落库】

// 设置分库分表路由
        try {
            // 以用户id为切分键,通过 dbRouter 设定路由
            dbRouter.doRouter(createQuotaOrderAggregate.getUserId());
            // 编程式事务
            transactionTemplate.execute(status -> {
                try{
                    // 1. 写入订单记录
                    raffleActivityOrderDao.insert(raffleActivityOrder);
                    // 2. 更新账户
                    int count = raffleActivityAccountDao.updateAccountQuota(raffleActivityAccount);
                    // 3. 账户不存在则创建新账户(分布式部署下可能调用的表中有这个用户,但是活动账户表中还没有写入)
                    if (0 == count) {
                        raffleActivityAccountDao.insert(raffleActivityAccount);
                        log.info("账户不存在,创建新账户");
                    }
                    return 1;
                } catch (DuplicateKeyException e) {
                    // 手动回滚
                    status.setRollbackOnly();
                    log.error("写入订单记录,唯一索引冲突orderId:{} OutBusinessNo:{}", activityOrderEntity.getOrderId(), activityOrderEntity.getOutBusinessNo());
                    throw new AppException(ResponseCode.INDEX_DUP.getCode(), ResponseCode.INDEX_DUP.getInfo());
                }
            });
        } finally {
            dbRouter.clear();
        }

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇