幼儿饰品瑜伽美体用品微软
投稿投诉
微软创意
爱情通信
用品婚姻
爱好看病
美体软件
影音星座
瑜伽周边
星座办公
饰品塑形
搞笑减肥
幼儿两性
智家潮品

GO编程DTM(二)

  二阶段消息例子
  本文将介绍一个完整的二阶段消息例子,让读者对二阶段消息型事务有一个准确的了解业务场景
  跨行转账是典型的分布式事务场景,在这里,A需要跨行转账给B,假设需求场景是:只有转出A可能失败,转入B是能够最终成功的二阶段消息
  二阶段消息是dtm首创的事务模式,用于替换本地事务表和事务消息这两种现有的方案。它能够保证本地事务的提交和全局事务提交是原子的,适合解决不需要回滚的分布式事务场景。下面我们来看看二阶段消息,如何解决这个业务场景的问题。核心业务
  首先我们创建账户余额表:CREATETABLEdtmbusi。useraccount(idint(11)AUTOINCREMENTPRIMARYKEY,useridint(11)notNULLUNIQUE,balancedecimal(10,2)NOTNULLDEFAULT0。00,tradingbalancedecimal(10,2)NOTNULLDEFAULT0。00,createtimedatetimeDEFAULTnow(),updatetimedatetimeDEFAULTnow());
  然后编写核心业务代码,调整用户的账户余额funcSagaAdjustBalance(dbdtmcli。DB,uidint,amountint,resultstring)error{,err:dtmimp。DBExec(db,updatedtmbusi。useraccountsetbalancebalance?whereuserid?,amount,uid)returnerr}
  再来编写具体的处理函数app。POST(BusiAPISagaBTransIn,dtmutil。WrapHandler2(func(cgin。Context)interface{}{barrier:MustBarrierFromGin(c)returnbarrier。Call(txGet(),func(txsql。Tx)error{returnSagaAdjustBalance(tx,TransInUID,reqFrom(c)。Amount,)})}))
  这些处理函数的核心逻辑都是是调整余额。这里面的barrier。Call主要是用于处理幂等,保证重复调用不会多次调整余额,详情参见异常与子事务屏障二阶段消息事务
  到此各个子事务的处理函数已经OK了,然后是开启二阶段消息事务,进行分支调用msg:dtmcli。NewMsg(DtmServer,shortuuid。New())。Add(busi。BusiSagaBTransIn,TransReq{Amount:30})err:msg。DoAndSubmitDB(busi。BusiQueryPreparedB,dbGet(),func(txsql。Tx)error{returnbusi。SagaAdjustBalance(tx,busi。TransOutUID,req。Amount)})
  这段代码中,会保证DoAndSubmitDB中的业务提交和全局事务提交是原子的,保证了TransOut和TransIn的同时成功,或同时失败。其中DoAndSubmitDB中的第一个参数为回查URL,他的代码如下:app。GET(BusiAPIQueryPreparedB,dtmutil。WrapHandler2(func(cgin。Context)interface{}{bb:MustBarrierFromGin(c)returnbb。QueryPrepared(dbGet())}))
  至此,一个完整的二阶段消息分布式事务编写完成。运行
  如果您想要完整运行一个成功的示例,步骤如下:运行dtmgitclonehttps:github。comdtmlabsdtmcddtmgorunmain。go运行例子gitclonehttps:github。comdtmlabsdtmexamplescddtmexamplesgorunmain。gohttpmsgdoAndCommit如何保证原子性
  二阶段消息如何保证本地事务和全局事务要么都成功,要么都失败呢?假定本地事务提交完成后,提交全局事务前,进程crash会如何?下面时序图很好的讲解了二阶段消息是如何处理这个问题的:
  图中的回查处理逻辑,dtm已经做了自动处理,用户只需要粘贴上述的代码即可SAGA例子
  本文将介绍一个完整的SAGA例子,让读者对SAGA型事务有一个准确的了解业务场景
  跨行转账是典型的分布式事务场景,在这里,A需要跨行转账给B,假设需求场景是:转出A和转入B都有可能成功和失败,需要最终转入转出都成功,或者都失败SAGA
  Saga是这一篇数据库论文SAGAS提到的一个分布式事务方案。其核心思想是将长事务拆分为多个本地短事务,由Saga事务协调器协调,如果各个本地事务成功完成那就正常完成,如果某个步骤失败,则根据相反顺序一次调用补偿操作。核心业务
  对于我们要进行的银行转账的例子,我们将在正向操作中,进行转入转出,在补偿操作中,做相反的调整。
  首先我们创建账户余额表:CREATETABLEdtmbusi。useraccount(idint(11)AUTOINCREMENTPRIMARYKEY,useridint(11)notNULLUNIQUE,balancedecimal(10,2)NOTNULLDEFAULT0。00,tradingbalancedecimal(10,2)NOTNULLDEFAULT0。00,createtimedatetimeDEFAULTnow(),updatetimedatetimeDEFAULTnow());
  然后编写核心业务代码,调整用户的账户余额funcSagaAdjustBalance(dbdtmcli。DB,uidint,amountint,resultstring)error{,err:dtmimp。DBExec(db,updatedtmbusi。useraccountsetbalancebalance?whereuserid?,amount,uid)returnerr}
  再来编写具体的正向操作补偿操作的处理函数app。POST(BusiAPISagaBTransIn,dtmutil。WrapHandler2(func(cgin。Context)interface{}{barrier:MustBarrierFromGin(c)returnbarrier。Call(txGet(),func(txsql。Tx)error{returnSagaAdjustBalance(tx,TransInUID,reqFrom(c)。Amount,)})}))app。POST(BusiAPISagaBTransInCom,dtmutil。WrapHandler2(func(cgin。Context)interface{}{barrier:MustBarrierFromGin(c)returnbarrier。Call(txGet(),func(txsql。Tx)error{returnSagaAdjustBalance(tx,TransInUID,reqFrom(c)。Amount,)})}))app。POST(BusiAPISagaBTransOut,dtmutil。WrapHandler2(func(cgin。Context)interface{}{barrier:MustBarrierFromGin(c)returnbarrier。Call(txGet(),func(txsql。Tx)error{returnSagaAdjustBalance(tx,TransOutUID,reqFrom(c)。Amount,)})}))app。POST(BusiAPISagaBTransOutCom,dtmutil。WrapHandler2(func(cgin。Context)interface{}{barrier:MustBarrierFromGin(c)returnbarrier。Call(txGet(),func(txsql。Tx)error{returnSagaAdjustBalance(tx,TransOutUID,reqFrom(c)。Amount,)})}))
  这些处理函数的核心逻辑都是是调整余额,对于这里面的barrier。Call作用,后面会详细解释SAGA事务
  到此各个子事务的处理函数已经OK了,然后是开启SAGA事务,进行分支调用req:gin。H{amount:30}微服务的载荷DtmServer为DTM服务的地址saga:dtmcli。NewSaga(DtmServer,shortuuid。New())。添加一个TransOut的子事务,正向操作为url:qsBusiTransOut,逆向操作为url:qsBusiTransOutComAdd(qsBusiSagaBTransOut,qsBusiSagaBTransOutCom,req)。添加一个TransIn的子事务,正向操作为url:qsBusiTransOut,逆向操作为url:qsBusiTransInComAdd(qsBusiSagaBTransIn,qsBusiSagaBTransInCom,req)提交saga事务,dtm会完成所有的子事务回滚所有的子事务err:saga。Submit()
  至此,一个完整的SAGA分布式事务编写完成。运行
  如果您想要完整运行一个成功的示例,步骤如下:运行dtmgitclonehttps:github。comdtmlabsdtmcddtmgorunmain。go运行例子gitclonehttps:github。comdtmlabsdtmexamplescddtmexamplesgorunmain。gohttpsagabarrier
  时序图如下:
  处理网络异常
  假设提交给dtm的事务中,调用转入操作时,出现短暂的故障怎么办?dtm会重试未完成的操作,此时就会要求全局事务中的各个子事务是幂等的。dtm框架首创子事务屏障技术,提供BranchBarrier工具类,可以帮助用户简单的处理幂等。它提供了一个函数Call,保证这个函数内部的业务,会被最多调用一次:func(bbBranchBarrier)Call(txsql。Tx,busiCallBarrierBusiFunc)error
  该BranchBarrier不仅能够自动处理幂等,还能够自动处理空补偿、悬挂的问题,详情可以参考异常与子事务屏障处理回滚
  假如银行将金额准备转入用户2时,发现用户2的账户异常,返回失败,会怎么样?我们调整处理函数,让转入操作返回失败app。POST(BusiAPISagaBTransIn,dtmutil。WrapHandler2(func(cgin。Context)interface{}{returndtmcli。ErrFailure}))
  我们给出事务失败交互的时序图
  这里有一点,TransIn的正向操作什么都没有做,就返回了失败,此时调用TransIn的补偿操作,会不会导致反向调整出错了呢?
  不用担心,前面的子事务屏障技术,能够保证TransIn的错误如果发生在提交之前,则补偿为空操作;TransIn的错误如果发生在提交之后,则补偿操作会将数据提交一次。
  您可以将返回错误的TransIn改成:app。POST(BusiAPISagaBTransIn,dtmutil。WrapHandler2(func(cgin。Context)interface{}{barrier:MustBarrierFromGin(c)barrier。Call(txGet(),func(txsql。Tx)error{returnSagaAdjustBalance(tx,TransInUID,reqFrom(c)。Amount,)})returndtmcli。ErrFailure}))
  最后的结果余额依旧会是对的,详情可以参考异常与子事务屏障TCC例子
  本文将介绍一个完整的TCC例子,让读者对TCC型事务有一个准确的了解业务场景
  跨行转账是典型的分布式事务场景,在这里,A需要跨行转账给B,假设需求场景是:转出A和转入B都有可能成功和失败,需要最终转入转出都成功,或者都失败。
  同时这里还有一个要求,假如发生回滚,SAGA模式下会发生A发现自己的余额被扣减了,但是收款方B迟迟没有收到余额,那么会对A造成很大的困扰。业务上面希望不要出现这种情况TCC组成
  TCC分为3个阶段Try阶段:尝试执行,完成所有业务检查(一致性),预留必须业务资源(准隔离性)Confirm阶段:如果所有分支的Try都成功了,则走到Confirm阶段。Confirm真正执行业务,不作任何业务检查,只使用Try阶段预留的业务资源Cancel阶段:如果所有分支的Try有一个失败了,则走到Cancel阶段。Cancel释放Try阶段预留的业务资源。
  如果我们要进行一个类似于银行跨行转账的业务,转出(TransOut)和转入(TransIn)分别在不同的微服务里,一个成功完成的TCC事务典型的时序图如下:
  核心业务
  首先我们创建账户余额表,其中tradingbalance表示被冻结的金额:createtableifnotexistsdtmbusi。useraccount(idint(11)PRIMARYKEYAUTOINCREMENT,useridint(11)UNIQUE,balanceDECIMAL(10,2)notnulldefault0,tradingbalanceDECIMAL(10,2)notnulldefault0,createtimedatetimeDEFAULTnow(),updatetimedatetimeDEFAULTnow(),key(createtime),key(updatetime));
  我们先编写核心代码,冻结解冻资金操作,会检查约束balancetradingbalance0,如果约束不成立,执行失败functccAdjustTrading(dbdtmcli。DB,uidint,amountint)error{affected,err:dtmimp。DBExec(db,updatedtmbusi。useraccountsettradingbalancetradingbalance?whereuserid?andtradingbalance?balance0,amount,uid,amount)iferrnilaffected0{returnfmt。Errorf(updateerror,maybebalancenotenough)}returnerr}functccAdjustBalance(dbdtmcli。DB,uidint,amountint)error{affected,err:dtmimp。DBExec(db,updatedtmbusi。useraccountsettradingbalancetradingbalance?,balancebalance?whereuserid?,amount,amount,uid)iferrnilaffected0{returnfmt。Errorf(updateuseraccount0rows)}returnerr}
  下面我们来编写具体的TryConfirmCancel的处理函数app。POST(BusiAPITccBTransOutTry,dtmutil。WrapHandler2(func(cgin。Context)interface{}{bb:MustBarrierFromGin(c)returnbb。Call(txGet(),func(txsql。Tx)error{returntccAdjustTrading(tx,TransOutUID,req。Amount)})}))app。POST(BusiAPITccBTransOutConfirm,dtmutil。WrapHandler2(func(cgin。Context)interface{}{bb:MustBarrierFromGin(c)returnbb。Call(txGet(),func(txsql。Tx)error{returntccAdjustBalance(tx,TransOutUID,reqFrom(c)。Amount)})}))app。POST(BusiAPITccBTransOutCancel,dtmutil。WrapHandler2(func(cgin。Context)interface{}{bb:MustBarrierFromGin(c)returnbb。Call(txGet(),func(txsql。Tx)error{returntccAdjustTrading(tx,TransOutUID,req。Amount)})}))app。POST(BusiAPITccBTransInTry,dtmutil。WrapHandler2(func(cgin。Context)interface{}{bb:MustBarrierFromGin(c)returnbb。Call(txGet(),func(txsql。Tx)error{returntccAdjustTrading(tx,TransInUID,req。Amount)})}))app。POST(BusiAPITccBTransOutConfirm,dtmutil。WrapHandler2(func(cgin。Context)interface{}{bb:MustBarrierFromGin(c)returnbb。Call(txGet(),func(txsql。Tx)error{returntccAdjustBalance(tx,TransInUID,reqFrom(c)。Amount)})}))app。POST(BusiAPITccBTransInCancel,dtmutil。WrapHandler2(func(cgin。Context)interface{}{bb:MustBarrierFromGin(c)returnbb。Call(txGet(),func(txsql。Tx)error{returntccAdjustTrading(tx,TransInUID,req。Amount)})}))
  到此各个子事务的处理函数已经OK了,这些处理函数的核心逻辑都是冻结和调整余额,对于这里面的bb。Call作用,后面会详细解释TCC事务
  然后是开启TCC事务,进行分支调用TccGlobalTransaction会开启一个全局事务,err:dtmcli。TccGlobalTransaction(DtmServer,func(tccdtmcli。Tcc)(rerrerror){CallBranch会将事务分支的ConfirmCancel注册到全局事务上,然后直接调用Tryres1,rerr:tcc。CallBranch(TransReq{Amount:30},hostapiTccBTransOutTry,hostapiTccBTransOutConfirm,hostapiTccBTransOutCanceliferr!nil{returnresp,err}returntcc。CallBranch(TransReq{Amount:30},hostapiTccBTransInTry,hostapiTccBTransInConfirm,hostapiTccBTransInCancel)})
  至此,一个完整的TCC分布式事务编写完成。运行
  如果您想要完整运行一个成功的示例,步骤如下:运行dtmgitclonehttps:github。comdtmlabsdtmcddtmgorunmain。go运行例子gitclonehttps:github。comdtmlabsdtmexamplescddtmexamplesgorunmain。gohttptccbarrier处理网络异常
  假设提交给dtm的事务中,这些步骤中,出现短暂的故障怎么办?dtm会重试未完成的操作,此时就会要求全局事务中的各个子事务是幂等的。dtm框架首创子事务屏障技术,提供BranchBarrier工具类,可以帮助用户简单的处理幂等。它提供了一个函数Call,保证这个函数内部的业务,会被最多调用一次:func(bbBranchBarrier)Call(txsql。Tx,busiCallBarrierBusiFunc)error
  该BranchBarrier不仅能够自动处理幂等,还能够自动处理空补偿、悬挂的问题,详情可以参考异常与子事务屏障TCC的回滚
  假如银行将金额准备转入用户2时,发现用户2的账户异常,返回失败,会怎么样?我们修改代码,模拟这种情况:app。POST(BusiAPITccBTransInTry,dtmutil。WrapHandler2(func(cgin。Context)interface{}{returndtmcli。ErrFailure}))
  这是事务失败交互的时序图
  这个跟成功的TCC差别就在于,当某个子事务返回失败后,后续就回滚全局事务,调用各个子事务的Cancel操作,保证全局事务全部回滚。
  这里有一点,TransInTry的正向操作什么都没有做,就返回了失败,此时调用TransInCancel补偿操作,会不会导致反向调整出错了呢?
  不用担心,前面的子事务屏障技术,能够保证TransInTry的错误如果发生在提交之前,则补偿为空操作;TransInTry的错误如果发生在提交之后,则补偿操作会将数据提交一次。
  您可以将TccBTransInTry改成app。POST(BusiAPITccBTransInTry,dtmutil。WrapHandler2(func(cgin。Context)interface{}{bb:MustBarrierFromGin(c)bb。Call(txGet(),func(txsql。Tx)error{returntccAdjustTrading(tx,TransInUID,req。Amount)})returndtmcli。ErrFailure}))
  最后的结果余额依旧会是对的,详情可以参考异常与子事务屏障

这种被忽略的维生素能抗肝癌,降低复发率阅读前请点击关注,每天都会定时发送健康资讯,让觅健陪您一起添增勇气,拥抱爱,抗癌路上不孤单说起维生素,觅友们都知道维生素是人体所必需的营养之一。不同类型的维生素对人体起着……中国球迷应当好好认识韩旭,这位闪耀WNBA的99年姑娘今天,WNBA结束了最后的常规赛,纽约自由人主场8783险胜亚特兰大梦想,成功进入季后赛。同时,国球员韩旭与李月汝将分别代表自由人和天空在季后赛首轮相遇,这是WNBA历史首次在……神十四乘组开展多项在轨科学实验央视网消息:目前,神舟十四号航天员乘组在轨工作生活将近三个月,各项工作顺利推进,已经展开了大量的在轨科学实验。核心舱内,高微重力实验柜等科学实验柜继续开展科学实验;问天舱内,航……暗影火炬城Switch版本评测抛开Switch版本的一些特性,我们简单回顾一下《暗影火炬城》的魅力。很明显这本书是一部极其标准的银河恶魔城式的作品。主角就像一个标记信号,你的视角将完全有权围绕它移动。在一个……近期有四款高端家电要降价,美的空调格力冰箱都在内,全是畅销款目前的家电市场处于上一波降价潮刚过,下一波降价潮未来的尴尬阶段,可能近期购买家电都会遇到价格虚高的问题。不过没关系,虽然没有大规模降价,但家电市场还是有很多单品存在可捡漏的情况……2022婚纱摄影最火风格大曝光,竟如此多人拍同款,还被称为小紧随潮流是当下快时代的必然要求,所以无论是行业还是个人,都在马不停蹄的学习、进步、转变,所以导致现在各种东西更新迭代都很快。数码产品的更替很快,但是现在美妆产品、审美标准等都成……MySQLselectcount()计数很慢,有没有优化方案在日常开发工作中,我经常会遇到需要统计总数的场景,比如:统计订单总数、统计用户总数等。一般我们会使用MySQL的count函数进行统计,但是随着数据量逐渐增大,统计耗时也越来越……徐威宠了袁立11年,为何转身娶了世界冠军张怡宁?我是被徐威宠坏的人。袁立说。当年,徐威也曾年轻过,也曾那么喜欢过一个人。可惜他和袁立还是分手了。徐威宠了袁立11年,转身娶了世界冠军张怡宁。如今,17年……我科学家发布首批大视场X射线聚焦成像天图8月27日,第二届中国空间科学大会上,来自中国科学院国家天文台的研究人员发布了EPWXT探路者的首批在轨实测结果。这是国际上首次获得并公开发布的宽视场X射线聚焦成像天图。……巴萨钉子户摊牌给500万遣散费,我就走人!巴萨能省200万巴萨VS曼城的热身赛,布莱斯维特连大名单都没有入选。巴萨铁了心要甩掉布莱斯维特,丹麦前锋也有回应。8月25日的《马卡报》透露,布莱斯维特向巴萨摊牌:给500万欧元遣散费,自己就……原神金字塔景观,赛诺图标暗示切换形态,妮露专武有种盾剑的美考虑到或许大家想要更快地看到3。1相关的爆料(其实是我自己更急),所以先把目前测试服刚发掘出来的消息分享给大家,至于妮露等人的详细技能信息以及新武器的具体数据等后续曝光再补充。……LPL两大独一档战队,TES和JDG实力领跑,北枫EDG紧随目前LPL夏季赛季后赛也是接近尾声的状态,那么不少观众朋友们也都在讨论到底这个赛季哪一支队伍能够夺冠,实际上目前整体看下来的话,几支队伍的实力比较的接近,比如TES和JDG,包……
金巧巧年龄越大越出众!穿粉色薄纱连衣裙气质开挂,短发也很优雅娱乐圈的女星真是个神奇的存在,即使人到中年,整个人的状态看起来就跟少女一样,活出了中年女人想要的姿态,越老越出众。这不,47岁的金巧巧以一身粉色薄纱裙亮相活动,整个人的姿态看起……雪藏大半主力换来平局,皮奥利是否太自负了?2019年米兰120周年庆典战之后,红黑军团再一次和萨索洛闷平。自信和自负,有时候真就是毫厘之差。出征马佩球场前一天,意大利天空体育曝料称皮奥利将在客场做大幅度轮换……当我听到神州十四号宇航员说我已出舱,感觉良好!我激动了据中国载人航天工程办公室消息,北京时间2022年9月1日18时26分,航天员陈冬成功开启问天实验舱气闸舱出舱舱门。至19时09分,航天员陈冬、航天员刘洋成功出舱。在党的正……女人过了50岁,卫衣才是最舒适的打扮,记住3要3不要更优雅对于上了年纪的女人,着装打扮的难点在于舒适与审美之间的平衡,那些穿着时髦且优雅的女性就懂得其中的真理。例如兼顾美貌与舒适度的卫衣,大多数人都只能穿出休闲运动感来,但会穿的女人却……中国排协回应女排队员在亚洲杯中戴口罩参赛新华社北京8月26日电在2022年女排亚洲杯小组赛中国对伊朗比赛中,中国队员第一局戴着口罩比赛引起社会的广泛关注和担心,对此,中国排球协会26日予以回应。图源:中国排协官……老公坠楼身亡,35岁女星王瞳丧礼上抱婚纱照痛哭,原定下月办婚8月24日,据媒体报道,40岁男星艾成17日坠楼身亡,时隔数日,35岁演员妻子王瞳为他举办丧礼。艾成曾夺得选秀比赛冠军,比赛结束后开始以歌手身份活跃于娱乐圈,工作过程中,……随身拍摄的便携镜头怎么选?头条创作挑战赛对摄影有一定追求的朋友基本都会拥有一台自己喜爱的照相机,但买了相机之后令人挠头的问题是:懒得带出去拍!这不是一个两个摄友的问题,而是一个普遍存在的问题……云南一农村摆酒席,为什么桌上的菜夹得少,酒却被喝个精光云南一农村摆酒席,为什么桌上的菜夹得少,酒却被喝个精光前几天在云南参加了一场宴席,办席的地点是一个农村。大家也都知道,这些年农村方方面面都在改造,修路修房,甚至连村里的民……金晨穿白色蕾丝花边裙,美背性感贵气十足金晨近日发布了一组写真自拍,照片里金晨穿一身白色性感长裙,美背白皙光滑,戴着首饰贵气十足。模特身材的金晨亭亭玉立,真的让人见了美若天仙,金晨高挑的个子真的很加分。黑……秋天的思念饭后,乘着小孩子外出消食的良机。我也匆匆的跑下楼梯,预备一个人好好的散散心,走走步!正是薄冥时分,天色半微半明。仰头望望,天际早已没了太阳的踪迹,只是紧挨着大山处,飘浮着……谁才是家用投影仪的内卷王ViddaC1和极米RSPro2对比现在的内卷真是无处不在,不过产品之间的内卷倒是给我们消费者提供了实实在在的性价比体验。比如今天的两位主角ViddaC1和极米RSPro2,均是定位旗舰级的4K家庭投影仪。这两个……定位纯电紧凑型车,7。5秒时速破百,小鹏P5顶配版适合年轻人说到年轻朋友的购车理念,相信大多数是看着车辆的颜值以及强劲的动力,什么空间呀,价格呀反倒是其次,这不,今天笔者就为各位年轻的朋友们推荐一款颜值高动力不差的车型,它就是小鹏P52……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网